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

題目描述:

有兩個日期,求兩個日期之間的天數,如果兩個日期是連續的我們規定他們之間的天數爲兩天

輸入:

有多組數據,每組數據有兩行,分別表示兩個日期,形式爲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等函數動態申請變量空間。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章