日期差值【九度教程第六题】

题目描述:

有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天

输入:

有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD

输出:

每组数据输出一行,即日期差值

样例输入:

20110412
20110422

样例输出:

11

来源:2009年上海交通大学计算机研究生机试真题

基本思路
  1. 统一区间:解决这类日期区间问题有一个统一的思想——把原区间问题统一到起点确定的区间问题上去。在该例中,不妨把问题统一到特定日期与一个原点时间(如0000年1月1日)的天数差,当要求两个特定的日期之间的天数差时,只要将它们与原点日期的天数差相减,便能得到这两个特定日期之间的天数差(必要时加绝对值)。
  2. 预处理:可以在程序真正开始处理输入数据之前,预处理出所有日期与原点日期之间的天数差并保存起来。当数据真正开始输入时只需要用O(1)的时间复杂度将保存的数据读出,稍加处理便能得到答案。
注意点
  1. 以什么数据结构存储日期年月日?
  2. 如何计算与标尺日期(0.1.1)的日期差?为什么不直接计算输入两行数据的日期差呢?
  3. 如何处理控制台的输入,即如何解析输入的一行数?(scanf咋用)如何处理多组数据的输入?
回答一下
  1. 用结构体存储,其中还包含了一个方法,该方法计算后一天的日期表示
  2. 对于每个日期(从0.1.1开始),可以利用一个计数器,再利用结构体中计算后一日的方法,依次往后推移,可以算出每个日期与标尺日期的差值,存放到一个数组中。
  3. 因为题面规定用一个连续的八位数来代替日期,使用%4d来读取该八位数的前四位并赋值给代表年的变量,同理使用%2d%2d来读取其它后四位并两两赋值给月日。这种利用在%d之间插入数字来读取特定位数的数字的技巧值得利用。scanf("%4d%2d%2d"
  4. 多组数据输入用scanf("%4d%2d%2d",&y1,&m1,&d1)!=EOF来控制
代码
#include<stdio.h>
#include<math.h>
int month_day[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 isrunyear(int year){
	return (year%400==0)||((year%100!=0)&&(year%4==0));
}
struct date{
	int year;
	int month;
	int day;
	void nextday(){
		day++;
		if(day>month_day[month][isrunyear(year)]){
			day=1;
			month++;
			if(month>12){
				month=1;
				year++;
			}
		}
	}
};// 定义结构体,中间含有一个方法 

	int buf[5001][13][32]; 
	/* 
	定义一个buf存放与标尺日期的天数差值 引用buf[2001][12][1]表示2001.12.1与标尺日期的天数差值
	其中每个多出一维是为了索引方便 
	*/ 
int main()
{
	date temp;

	temp.year=0;
	temp.month=1;
	temp.day=1; //标尺日期0.1.1
	int cnt=0; //日期计数,计算当前日期与标尺的差 
	//填充buf数组,计算所有日期与标尺的差 
	while(temp.year!=5001){
		buf[temp.year][temp.month][temp.day]=cnt;
		temp.nextday();
		cnt++; 	 
	}
	
	int y1,m1,d1;
	int y2,m2,d2;
	int res;
	while(c){
		//scanf("%4d%2d%2d",&y1,&m1,&d1);
		scanf("%4d%2d%2d",&y2,&m2,&d2);
		res = abs(buf[y1][m1][d1] - buf[y2][m2][d2])+1;
		printf("%d\n",res);
	}
	return 0;
}

可以看到,还是有几个注意点:

  1. 闰年的判断条件:四年一闰,百年不闰,四百年又闰
  2. 日期结构体中定义了一个内置函数(java类里的方法),该方法能够计算下一个日期:当前结构体日期为0.1.1,那么调用了该函数(tmp.nextday())之后,当前结构体的日期就会变为0.1.2,当前的tmp结构体的各个字段的值会发生改变
  3. 直接引用数组值(查表)
    • 将闰年和平年的每个月的天数存放在一个二维数组中,用闰年判断条件来决定取哪一列
    • 使用三维数组保存与原点日期的天数差时,用年、月、日分别表示该数组下标,这便将日期本身与其存储地址联系了起来,这样在存取时不必再为查找其所在的存储地址而大费周章,而只需要直接利用它的年月日数字即可找到我们保存的值
  4. 二维数组和三维数组的长度:可以发现多了一维,这是为了索引的方便:当前month=1,那么直接调用[month]就可以访问到该月的对应天数,三维数组也是一样的道理。
  5. 大数组定义成全局变量:将buf[5001][13][32]这个相对比较耗费内存的数组定义成全局变量。由于需要耗费大量的内存,若在main函数(其它函数也一样)之中定义该数组,其函数所可以使用的栈空间将不足以提供如此庞大的内存,出现栈溢出,导致程序异常终止。所以凡是涉及此类需要开辟大量内存空间的情况,都必须在函数体外定义,即定义为全局变量。或者在函数中使用malloc等函数动态申请变量空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值