【算法训练】日期类

日期类问题

总的来说,日期类的问题,应当先进行数据预处理,通过转化为对统一日期差值的求解

1、例题 日期差值
题目描述>有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们 之间的天数为两天 输入>有多组数据,每组数据有两行,分别表示两个日期输出

每组数据输出一行,即日期的差值样例输入
20110412
20110422样例输出
11

预处理思想
要解决的问题是天数差,解决这类问题的统一思想是把原区间问题统一到起点确定的区间问题上去
在本例中将问题统一到特定日期与原点时间(如0000年1月1日)的天数差,当要求两个特定日期的天数差时,
只需要将他们与原点时间的天数差相减,便能得到这两个特定日期之间的天数差(必要时加绝对值)
日期问题需要注意的一点是闰年二月天数的问题,判断规则——当年数不能被100整除且能够被4整除为闰年,或能够被400整除为闰年。

#include<stdio.h>
int isYeap(int x){//用于判断是否为闰年,以计算每月的天数 
    int flag;
    flag=((x%100!=0 && x%4==0) || (x%400==0)) ? 1:0;
}
int dayOfMonth[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
} ;//预存每个月的天数,注意二月
struct Date{//日期类,方便推算日期 
    int Day;
    int Month;
    int Year;
    void nextDay(){
        Day++;
        if(Day>dayOfMonth[Month][isYeap(Year)]){//若日期超过当月最大天数 
            Day=1;
            Month++;//进入下一月 
            if(Month>12){//若月份超过12 
                Month=1;
                Year++; //进入下一年 
            }
        }
    }
}; 
int buf[5001][13][32];//保存预处理天数
int Abs(int x){
    return x<0? -x:x;
} 
int main(){
    Date tmp;
    int cnt=0;//计天数
    tmp.Day=1;
    tmp.Month=1;
    tmp.Year=0;//初始化日期类对象为0年1月1日
    while(tmp.Year!=5001){
        //日期不超过5000年
        buf[tmp.Year][tmp.Month][tmp.Day]=cnt;//将该日与0年1月1日的天数差保存起来
        tmp.nextDay();//计算下一天日期
        cnt++;//计数器累加,每经过一天计数器+1,代表与原点日期间隔又增加一天 
    } 
    int d1,m1,y1;
    int d2,m2,y2;
    int k; 
    while(scanf("%4d%2d%2d",&y1,&m1,&d1)!=EOF){
        scanf("%4d%2d%2d",&y2,&m2,&d2);//输入要计算的两个日期
        k=buf[y2][m2][d2]-buf[y1][m1][d1];
        printf("%d\n",Abs(k)+1);//用预处理的数据计算两日期差值,注意需对其求绝对值
         
    } 
    return 0;
}

其一,我们使用了三维数组, 用年、月、日分别表示该数组下标,这便将日期本身与其存储地址联系了起来, 这样我们在存取时不必再为查找其所在的存储地址而大费周章,而只需要直接利 用它的年月日数字即可找到我们保存的值。将数据本身与数据存储地址联系起 来,这是Hash的基本思想
其二,因为题面规定用一个连续的八位数来 代替日期,我们使用%4d来读取该八位数的前四位并赋值给代表年的变量,同理 使用%2d%2d 来读取其它后四位并两两赋值给月日
其三,将 buf[5001][13][32]这个相对比较耗费内存的数组定义成全局变量
2.星期几问题
大意为,输入一个日期,求该日期为星期几
样例输入

9 October 2001
14 October 2001样例输出
Tuesday
Sunday

找一天为标准,计算给定日期与该日期的差值,本例中,我找了2019.7.15为星期一,下标为1.则下标加上days后再对7求余,其中注意到可能days为负数的情况

#include<stdio.h>
#include<string.h>
int isYeap(int x){//用于判断是否为闰年,以计算每月的天数 
    int flag;
    flag=((x%100!=0 && x%4==0) || (x%400==0)) ? 1:0;
}
int dayOfMonth[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
} ;//预存每个月的天数,注意二月
struct Date{//日期类,方便推算日期 
    int Day;
    int Month;
    int Year;
    void nextDay(){
        Day++;
        if(Day>dayOfMonth[Month][isYeap(Year)]){//若日期超过当月最大天数 
            Day=1;
            Month++;//进入下一月 
            if(Month>12){//若月份超过12 
                Month=1;
                Year++; //进入下一年 
            }
        }
    }
};
int buf[3001][13][32];
char monthName[13][20]={
    "",
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December" 
};
char weekName[7][20]={
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"};//周名 每个周名对应下标0-6
int main(){
    Date tmp;
    int cnt=0;//计天数
    tmp.Day=1;
    tmp.Month=1;
    tmp.Year=0;//初始化日期类对象为0年1月1日
    while(tmp.Year!=3001){
        //日期不超过3000年
        buf[tmp.Year][tmp.Month][tmp.Day]=cnt;//将该日与0年1月1日的天数差保存起来
        tmp.nextDay();//计算下一天日期
        cnt++;//计数器累加,每经过一天计数器+1,代表与原点日期间隔又增加一天 
    }  
    int d,m,y;
    char s[20];
    while(scanf("%d%s%d",&d,s,&y)!=EOF){
        for(m=1;m<=12;m++){
            if(strcmp(s,monthName[m])==0){
                break;
            }
        }
        int days=buf[y][m][d]-buf[2019][7][15];
        days+=1;//2019.7.15为星期一,对应数组下标为1,则计算1经过days天后的下标 
        
        printf("%s",weekName[(days%7+7)%7]);//将计算后得出的下标用7对其取模,并保证其为非负数,则该下标为答案所对应的下标 
    }
    return 0;
    
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值