首页 > 学院 > 开发设计 > 正文

codeup 1928 日期差值

2019-11-11 03:05:03
字体:
来源:转载
供稿:网友

日期处理问题真是让人感到头疼,需要非常细心的去处理细节。(但是看了《算法笔记》上的解法,我觉得方法才是最重要的……)

下面以codeup上的一道题来介绍相关问题,以及从中习得的一些新的知识点。题目如下:

题目描述有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。输入有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD输出每组数据输出一行,即日期差值样例输入2013010120130105样例输出5

非常常规的一道题目,验证了“细节处理非常重要”这句话,但是更加验证了“方法更重要”这句话。

题目分析

首先,分析一下这个题目。我们需要做的事情有如下:1. 处理日期的输入2. 如何计算两个日期的差值

处理日期的输入

我的方法

我想到的是用之前刚刚学会的sscanf 来处理输入,如下:

char time1[10],time2[10];scanf("%s",time1);scanf("%s",time2);int year1,month1,day1;int year2,month2,day2;sscanf(time1,"%4d%2d%2d",&year1,&month1,&day1);sscanf(time2,"%4d%2d%2d",&year2,&month2,&day2);

这种方法乍一看是可以的,不过事实上也的确可以。我们获取输入的目的无非就是想要把年、月、日拿出来,而这种方法已经达到了这样的一个目的。

不过为了而后面的程序,我们必须把time1和time2分出个大小来,而这种拿法刚开始我认为在比较time1和time2大小上非常麻烦,需要有很多的分支判断。再写这篇文章的时候才猛然醒悟,类比后面的方法,此处的比较大下可以直接用串比较函数(strcmp函数)进行比较即可,亲测可行。

《算法笔记》处理输入的方法

下面给出《算法笔记》上处理输入的方法,自己没想到上面所说的字符串比较方法之前,觉得这个方法真实无比的巧妙啊!代码如下:

int time1, time2; //time1存小时间,time2存大时间int year1,month1,day1, year2,month2,day2;scanf("%d%d",&time1, &time2) if(time1 > time2){//保证time1存小时间,time2存大时间 int temp = time1; time1 = time2; time2 = temp; } // 除法(10^(n+1))拿到前面的n位数,模拿到后面n位数 year1 = time1/10000; month1 = time1%10000/100; day1 = time1%100; year2 = time2/10000; month2 = time2%10000/100; day2 = time2%100;

从代码可以看出,直接用两个整形变量拿到time1和time2,之后用除法和取模运算,拿到相应的位数。

经过反思,我发现我之所以没有想到这种方法,根本原因是在于对除法和取模运算的本质掌握不够透彻,从这里得出一个结论:

结论:除法和取模运算可以用来获取一个整形数的对应的位数,且存在如下规律:- 若想获取整数X的前N位,则用X/10(N+1)- 若想获得整数X的后N位,则用X%10(N+1)

这么一来,这两种方法可以说是殊途同归了,关键点还是回到了如何计算两年的时间差。

计算日期的差值

我的想法

首先是我自己的第一想法,比如输入为20160328和20110118这两个日期,我的想法是分成三部分进行计算,总天数 = 20120101-20160101这一大块时间 + 20160101-20160328这段时间 + 20110118-20111231这段时间,这种方法需要考虑的细节特别多,毫无意外我败了……

后来想到的方法是用一个“标志时间”,比如说19700101,然后分别计算输入的两个日期距离这个“标志时间”的天数x和y,最后结果就是x-y(或者其他的关系,总值是两个距离的差值,相信读者能懂)。这个方法没有去实现,因为我看了下面的方法,真是太神奇,太巧妙了!不过也仅仅是按照“实际情况”而已。

《算法笔记》计算两日期差值的方法

正如前一段的最后一句话,《算法笔记》中的方法仅仅是按照时间递进的“实际情况”来进行模拟而已。(我想,这也是为什么晴神把日期问题放在第三章入门模拟的原因吧……)

什么叫做“按照时间递进的实际情况”呢?就是从晓得日期time1一天一天的过到time2,也许说的不够明白,下面请看代码:

int sum = 1;//初始值为1而不是0while(year1<year2 || month1<month2 || day1<day2){ day1++; if(day1 > monthNum[month1][isLeapYear(year1)]){ month1++; day1 = 1;//注意点 } if(month1 > 12){ year1++; month1 = 1;//注意点 } sum++;}

相信看到代码就能够理解上面的感悟了。

其中,isLeapYear()是一个判断是否是闰年的函数bool isLeapYear(int year){ return ( (year%4 == 0 && year%100 != 0) || (year % 400 == 0) );}monthNum是一个数组int monthNum[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} };

这个方法所有的巧妙之处几乎都体现在上面这两段代码中,请读者自行体会其中的精妙。

完整代码

#include<stdio.h>bool isLeapYear(int year);int monthNum[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} }; int main(){ int time1, time2; //time1存小时间,time2存大时间 int year1,month1,day1, year2,month2,day2; while(scanf("%d%d",&time1, &time2) != EOF) { if(time1 > time2){ int temp = time1; time1 = time2; time2 = temp; } // 除法(10^(x+1))拿到前面的x位数,模拿到后面x位数 year1 = time1/10000; month1 = time1%10000/100; day1 = time1%100; year2 = time2/10000; month2 = time2%10000/100; day2 = time2%100; int sum = 1; while(year1<year2 || month1<month2 || day1<day2){ day1++; if(day1 > monthNum[month1][isLeapYear(year1)]){ month1++; day1 = 1; } if(month1 > 12){ year1++; month1 = 1; } sum++; } PRintf("%d/n",sum); } return 0;}bool isLeapYear(int year){ return ( (year%4 == 0 && year%100 != 0) || (year % 400 == 0) );}

《算法笔记》购买地址。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表