题目如下
y年m月d日是哪一年的第几天。
比如y年的1月1日是那一年的第一天,那么2000年7月7日是那一年的第几天。
以下程序实现了该功能,请你补全空白处代码:
#include <cstdio> #include <algorithm> using namespace std; int month[13][2] = {{0, 0}, {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}}; bool isleap(int year) { return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); } int main() { int y1, m1, d1; int y2, m2, d2; int time1, time2; scanf("%d%d", &time1, &time2); if (time1 > time2) swap(time1, time2); y1 = time1 / 10000, m1 = time1 % 10000 / 100, d1 = time1 % 100; y1 = time2 / 10000, m2 = time2 % 10000 / 100, d2 = time2 % 100; int ans = 1; while (y1 < y2 || m1 < m2 || d1 < d2) { d1++; _________________; ans++; } printf("%d\n", ans); return 0; }
题目分析
正常博主都是先给出最终答案,然后才开始分析具体实现,今天咱们先分析下这个题目,因为可能会误导一部分人。题目中给出的是计算某个日期是当年的第几天,而代码中却存在两个日期,解释下原因,题目中计算的是两个日期之间相差多少天,这多少和题目本意还是差了点意思,为了让大家两种都能学习到,这里博主把两种方式的代码都来解读分析下。
第一种:当前日期是当年的第几天
代码如下:
#include<iostream> using namespace std; int Num(int y, int m, int d) { int flag = 0; if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) { flag = 1; } vector<int>arr{ 31,28,31,30,31,30,31,31,30,31,30,31 }; if (m == 1) return d; else if (m == 2) return arr[m - 1] + d; else return accumulate(arr.begin(), arr.begin() + m - 1, 0) + flag + d; } int main() { cout << Num(2000, 7, 7);//189 }
1.判断平年和闰年
int flag = 0; if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) { flag = 1; }
这个比较简单,应该没有看不懂的吧?默认跳过了。
2. 计算天数
vector<int>arr{ 31,28,31,30,31,30,31,31,30,31,30,31 }; if (m == 1) return d; else if (m == 2) return arr[m - 1] + d; else return accumulate(arr.begin(), arr.begin() + m - 1, 0) + flag + d;
罗列出平年每一月的天数后:
如果是1月,日期就是第几天;
如果是2月,arr[m-1]+d就是天数;
其他月份,当前月前面的所有天数相加,再加上当前月的日,如果是闰年,需要额外+1,flag已经做出了判断。
说下accumulate:
int sum = accumulate(array.begin() , array.end() , 0);
accumulate 有三个参数:头两个参数是要累加的元素范围,第三个参数是累加的初始值。
accumulate 函数将它的一个内部变量设置为一个指定的初始值,然后在此初值上累加输入范围内所有元素的值。accumulate 算法返回累加的结果,其返回类型就是其第三个实参的类型。
accumulate还可用于拼接字符串:
string str = accumulate(array.begin() , array.end() , string(""));
到这里,第一种单纯算天数的解法就结束了,是不是很简单呢?接下来,我们开始第二种,计算距离某个日期的天数。
第二种:当前日期距某个日期的天数
代码如下:
#include <cstdio> #include <algorithm> using namespace std; int month[13][2] = {{0, 0}, {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}}; bool isleap(int year) { return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); } int main() { int y1, m1, d1; int y2, m2, d2; int time1, time2; scanf("%d%d", &time1, &time2); if (time1 > time2) swap(time1, time2); y1 = time1 / 10000, m1 = time1 % 10000 / 100, d1 = time1 % 100; y2 = time2 / 10000, m2 = time2 % 10000 / 100, d2 = time2 % 100; int ans = 1; while (y1 < y2 || m1 < m2 || d1 < d2) { d1++; if (d1 == month[m1][isleap(y1)] + 1) { d1 = 1; m1++; } if (m1 == 13) { m1 = 1; y1++; } ans++; } printf("%d\n", ans); return 0; }
这是题目中给出的代码补全后的样子,个人认为还有优化提升空间,简化步骤,大家自行思考。
1. 判断平闰年
int month[13][2] = {{0, 0}, {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31}}; bool isleap(int year) { return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); }
判断平闰年不是个难事,不多加说明,说说这个多维数组吧,很有意思啊,其实也就是按照月份,每个月在平闰年的天数,第0月用0补齐,说实话,觉得有些鸡肋了。
2.日期处理
int y1, m1, d1; int y2, m2, d2; int time1, time2; scanf("%d%d", &time1, &time2); if (time1 > time2) swap(time1, time2); y1 = time1 / 10000, m1 = time1 % 10000 / 100, d1 = time1 % 100; y2 = time2 / 10000, m2 = time2 % 10000 / 100, d2 = time2 % 100;
这里输入两个日期,time1大于time2,则交换两个日期,而且题目中y2也写成了y1,此处已纠正,并已经找官方修改。
由于输入的日期是不带分隔符的数字,比如:2022.08.28,输入是20220828,所以为了获取到年月日,需要按照上面的方式整除或者整除取余来获取年月日。
3.运算部分
int ans = 1; while (y1 < y2 || m1 < m2 || d1 < d2) { d1++; if (d1 == month[m1][isleap(y1)] + 1) { d1 = 1; m1++; } if (m1 == 13) { m1 = 1; y1++; } ans++; }
ans是天数,默认为1。
y1 < y2 || m1 < m2 || d1 < d2这是前提,如果想等,就是计算到头了。
判断1:
d1++,d1 == month[m1][isleap(y1)] + 1,判断平润年,从month的二位数组中取出对应年份对应月份的天数,+1是判断d1超出了这个月的最大天数,这时候就到下个月了,m1要+1,d1要重置为下个月的1号。
判断2:
m1=13,则带白哦要进入下一年了,进入下一年,年份y1+1,月份m1重置为1.
然后每次运算,ans++,直到y1=y2,m1=m2,d1=d2,则退出while循环,输出最终天数ans。
总结:
这道题难度不高,主要还是一个细心,考研对平闰年的判断和逻辑的思考方式,题目给的不是很明确,没搞懂的话很容易进入思维误区。有问题,欢迎评论区留言讨论。