昨天在微信里面看到一道题,赛题是华为【开发者英雄大会】寻找超级算法大师-DevCloud赛道出的,活动地址。
赛题为:
赛题蛮中规中矩的,涉及不到高深的算法,就是计算两日期之间的日期差距。看了网上的一些代码大多都是先计算当年的剩余日子+末尾年开始的日子+中间年份的日子。虽然好理解,但是写出来还是蛮复杂的,要注意闰年的情况。
这里给出一种新的思路:先分别计算两个日期距离公元元年之间的日子,然后将得到的两个日子相减就能得到两日期之间相差的天数了。而计算与公元元年之间的差距是很好计算的,只需要一个数学公式就可以了。我们就是2016-12-22为例子说明一下。首先计算2016年1月1日之前的天数,先假设每年只有365天,那么一共有(2016 - 1)* 365天。然后在计算2016年之前一共有多少个闰年,一共有
(2016 - 1)/ 4 - (2016 - 1) / 100 +(2016 - 1) / 400 个闰年。每个闰年比平年多一天,那么2016年之前一共有
(2016 - 1)* 365 + (2016 - 1)/ 4 - (2016 - 1) / 100 +(2016 - 1) / 400 天。然后在计算2016年过了多少天,这个就比较简单了,之间看代码就好了。
提交的代码如下:
/*
*计算两个日期之间的距离天数。
*本算法的思想是首先分别计算两个日期距离公元元年之间的日期天数,然后将得到的结果相减,即可得到两日期之间的距离天数。
*时间复杂度O(1),空间复杂度O(1).
*/
#include <bits/stdc++.h>
using namespace std;
//判断是否为闰年
bool isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
//1-11月份的累计天数
int days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
//计算当前日期与公元元年之间的日期天数
int dayOffset(int year, int month, int day) {
int res = (year - 1) * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + days[month - 1] + day;
return isLeapYear(year) && month > 2 ? res + 1 : res;
}
//判断输入的日期是否合法
bool checkDate(int year, int month, int day) {
if(year <= 0 || month <= 0 || day <= 0 || month > 12 || day > 31) {
return false;
} else if(day == 31) {
if(month != 1 || month != 3 || month != 5 || month != 7 || month != 8
|| month != 10 || month != 12) {
return false;
}
} else if(month == 2 && (day == 30 || day == 29 && !isLeapYear(year))) {
return false;
}
return true;
}
int main()
{
int year = -1;
int month = -1;
int day = -1;
//输入数据
cin >> year;cin.ignore();
cin >> month;cin.ignore();
cin >> day;
if(!checkDate(year, month, day)) {
cout << "Input illegal date!";
return 1;
}
cout << dayOffset(year, month, day) - 736320; //736320是2016年12月22日距离公元元年的日期距离,使用上面的函数计算得出。
return 0;
}