題目描述:
有兩個日期,求兩個日期之間的天數,如果兩個日期是連續的我們規定他們之間的天數爲兩天
輸入:
有多組數據,每組數據有兩行,分別表示兩個日期,形式爲YYYYMMDD
輸出:
每組數據輸出一行,即日期差值
樣例輸入:
20110412
20110422
樣例輸出:
11
來源:2009年上海交通大學計算機研究生機試真題
基本思路
- 統一區間:解決這類日期區間問題有一個統一的思想——把原區間問題統一到起點確定的區間問題上去。在該例中,不妨把問題統一到特定日期與一個原點時間(如0000年1月1日)的天數差,當要求兩個特定的日期之間的天數差時,只要將它們與原點日期的天數差相減,便能得到這兩個特定日期之間的天數差(必要時加絕對值)。
- 預處理:可以在程序真正開始處理輸入數據之前,預處理出所有日期與原點日期之間的天數差並保存起來。當數據真正開始輸入時只需要用O(1)的時間複雜度將保存的數據讀出,稍加處理便能得到答案。
注意點
- 以什麼數據結構存儲日期年月日?
- 如何計算與標尺日期(0.1.1)的日期差?爲什麼不直接計算輸入兩行數據的日期差呢?
- 如何處理控制檯的輸入,即如何解析輸入的一行數?(scanf咋用)如何處理多組數據的輸入?
回答一下
- 用結構體存儲,其中還包含了一個方法,該方法計算後一天的日期表示
- 對於每個日期(從0.1.1開始),可以利用一個計數器,再利用結構體中計算後一日的方法,依次往後推移,可以算出每個日期與標尺日期的差值,存放到一個數組中。
- 因爲題面規定用一個連續的八位數來代替日期,使用%4d來讀取該八位數的前四位並賦值給代表年的變量,同理使用%2d%2d來讀取其它後四位並兩兩賦值給月日。這種利用在%d之間插入數字來讀取特定位數的數字的技巧值得利用。
scanf("%4d%2d%2d"
- 多組數據輸入用
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;
}
可以看到,還是有幾個注意點:
- 閏年的判斷條件:四年一閏,百年不閏,四百年又閏
- 日期結構體中定義了一個內置函數(java類裏的方法),該方法能夠計算下一個日期:當前結構體日期爲0.1.1,那麼調用了該函數
(tmp.nextday())
之後,當前結構體的日期就會變爲0.1.2,當前的tmp結構體的各個字段的值會發生改變 - 直接引用數組值(查表):
- 將閏年和平年的每個月的天數存放在一個二維數組中,用閏年判斷條件來決定取哪一列
- 使用三維數組保存與原點日期的天數差時,用年、月、日分別表示該數組下標,這便將日期本身與其存儲地址聯繫了起來,這樣在存取時不必再爲查找其所在的存儲地址而大費周章,而只需要直接利用它的年月日數字即可找到我們保存的值。
- 二維數組和三維數組的長度:可以發現多了一維,這是爲了索引的方便:當前month=1,那麼直接調用[month]就可以訪問到該月的對應天數,三維數組也是一樣的道理。
- 大數組定義成全局變量:將
buf[5001][13][32]
這個相對比較耗費內存的數組定義成全局變量。由於需要耗費大量的內存,若在main函數(其它函數也一樣)之中定義該數組,其函數所可以使用的棧空間將不足以提供如此龐大的內存,出現棧溢出,導致程序異常終止。所以凡是涉及此類需要開闢大量內存空間的情況,都必須在函數體外定義,即定義爲全局變量。或者在函數中使用malloc等函數動態申請變量空間。