題目
例 2.3 日期差值 (九度教程第 6 題)
時間限制:1 秒 內存限制:32 兆 特殊判題:否
題目描述:
有兩個日期,求兩個日期之間的天數,如果兩個日期是連續的我們規定他們
之間的天數爲兩天
輸入:
有多組數據,每組數據有兩行,分別表示兩個日期,形式爲 YYYYMMDD
輸出:
每組數據輸出一行,即日期差值
樣例輸入:
20110412
20110422
樣例輸出:
11
來源:
2009 年上海交通大學計算機研究生機試真題
思路
把問題統一到特定日期與一個原點時間(如 0000 年 1 月 1 日)
的天數差,當要求兩個特定的日期之間的天數差時,我們只要將它們與原點日期
的天數差相減,便能得到這兩個特定日期之間的天數差(必要時加絕對值)。這
樣做有一個巨大的好處——預處理。我們可以在程序真正開始處理輸入數據之
前,預處理出所有日期與原點日期之間的天數差並保存起來。當數據真正開始輸
入時,我們只需要用 O(1)的時間複雜度將保存的數據讀出,稍加處理便能得
到答案。值得一提的是,預處理也是空間換時間的重要手段(保存預處理所得數
據所需的內存來換取實時處理所需要的時間消耗)。
代碼
#include<iostream>
#define ISLEAPYEAR(x) x % 100 != 0 && x % 4 == 0 || x % 400 == 0 ? 1 : 0 //簡潔寫法
using namespace std;
int DaysOfMonth(int month, int year)
{
switch(month)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
return 31;
break;
case 4: case 6: case 9: case 11:
return 30;
break;
case 2:
if(ISLEAPYEAR(year)) return 29;
else return 28;
}
}
class Date //注意不要加括號
{
public:
int year;
int month;
int day;
Date() //初始化日期爲0/1/1 作爲基準
{
year = 0;
month = 1;
day = 1;
}
void update() //將日期加一天
{
day++;
if(day > DaysOfMonth(month, year))
{
day = 1;
month ++;
if(month > 12)
{
month = 1;
year ++;
}
}
}
};
int Abs(int x)
{
return (x >= 0 ? x : -1*x);
}
int buf[6001][13][32]; //用來存儲每個日期與基準日期的差值
int main()
{
Date temp;
int count = 0;
while(temp.year < 6000)
{
buf[temp.year][temp.month][temp.day] = count;
temp.update();
count ++;
}
int y1, m1, d1, y2, m2, d2;
while(scanf("%4d%2d%2d", &y1, &m1, &d1) != EOF) //此處注意對於格式的控制
{
scanf("%4d%2d%2d", &y2, &m2, &d2);
cout << Abs(buf[y2][m2][d2] - buf[y1][m1][d1] + 1) << endl;
}
return 0;
}
總結
- 類名不要加括號
- 注意此題以空間換時間的思想
- 注意此題的宏定義函數寫法
- 對於輸入格式的控制%4d
- 在保存某個特定日期與原點日期的天數差時,我們使用了三維數組,用年、月、日分別表示該數組下標,這便將日期本身與其存儲地址聯繫了起來
- 我們將 buf[5001][13][32]這個相對比較耗費內存的數組定義成**全局變
量,**這不是偶然的。由於需要耗費大量的內存,若在 main 函數(其它函數也一樣)之中定義該數組,其函數所可以使用的棧空間將不足以提供如此龐大的內存出現棧溢出,導致程序異常終止。所以,今後凡是涉及此類需要開闢大量內存空間的情況,我們都必須在函數體外定義,即定義爲全局變量。或者在函數中使用malloc等函數動態申請變量空間。讀者必須牢記這一點。