日期处理与进制转换问题

这篇文章将介绍常见的日期处理与进制转换问题。

1.日期处理

以题目为例:http://codeup.hustoj.com/problem.php?cid=100000578&pid=0

问题 A: 日期差值

题目描述

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

输入

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

输出

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

样例输入

1
2
20130101
20130105

样例输出

1
5

细节

我们需要处理平年和闰年,大月和小月的问题。

思路

我们不妨设第一个日期是早于第二个日期的(如果不是就交换顺序)。

求日期差值的问题很直接的一个思路就是让第一个日期不断加1天,直到和第二个日期相等为止。

为了存放平年和闰年每个月的天数,我们建立一个二维数组int month[13][2],第一维存放月份,从1到12,第0位不用,第二维为0表示平年,为1表示闰年。

我们可以先让第一个日期的年份加到与第二个日期的年份相差1为止,这样可以加快速度。对于其中的年份,只要根据平年还是闰年加365或366天即可。之后再不断让天数加1就行。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

bool isLeap(int y){
return (y%4==0 &&y%100!=0) || (y%400==0);
}
int month[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}
};
int main()
{
int time1,time2;
int y1,m1,d1;
int y2,m2,d2;
while(scanf("%d%d",&time1,&time2) != EOF){// 有多组测试数据
int ans = 1;
if (time1 > time2) swap(time1,time2);
if(time1 == time2) {printf("%d\n",1);continue;}

y1 = time1/10000,m1 = time1%10000/100,d1 = time1%100;
y2 = time2/10000,m2 = time2%10000/100,d2 = time2%100;
// if (isLeap(y1) && m1 <= 2) ans += 1;
while (y1 < y2 || m1 < m2 || d1 < d2){
if (y1 < y2 -1){ // 优化判断
y1 ++;
if (isLeap(y1)) ans+=366;
else ans += 365;
continue;
}
d1++; // 注意这里放优化判断之后
if (d1==month[m1][isLeap(y1)]+1){
d1 = 1;m1++;
}
if (m1 == 13){
m1 = 1;y1++;
}
ans++;
}
printf("%d\n",ans);
}
return 0;
}

优化代码参考:https://blog.csdn.net/numb123r/article/details/112722689

优化代码经过测试,存在漏洞,“20200229;20220301”这组数据会少一天,好像从闰年开始日期<=2月都会少一天。

CODEUP的数据应该不完整,上面这组数据和优化前代码答案不一样,但都能过。

把25行代码解注释应该就是正确答案,但是AC不了(疑惑)。

直接硬算是最靠谱的,不需要对年数优化。

这题一般写法还是比较简单,但是优化时WA好几发,注意写法。

2.进制转换

以题目为例:

https://pintia.cn/problem-sets/994805260223102976/problems/994805299301433344

1022 D进制的A+B (20 分)

输入两个非负 10 进制整数 A 和 B (≤2^30−1),输出 A+B 的 D (1<D≤10)进制数。

输入格式:

输入在一行中依次给出 3 个整数 A、B 和 D。

输出格式:

输出 A+B 的 D 进制数。

输入样例:

1
123 456 8

输出样例:

1
1103

思路

将一个P进制数转换为Q进制数,分两步:

  1. 将P进制数x转换为10进制数y:
1
2
3
4
5
6
int y = 0,product = 1;
while (x!=0){// 也可以用位运算处理
y += (x%10)*product; // x%10取最后一位数
x /= 10; // 舍去x的最后一位数
product *= P; // product作为权
}

搞不清楚的话,可以拿二进制数转换为十进制数作为参考。

  1. 将10进制数y转换为Q进制数z:

除基取余法。

1
2
3
4
5
int z[40],num = 0; // 数组z用于存放Q进制数y的每一位,num为位数
do{
z[num++] = y % Q;
y /= Q;
}while (y != 0);

最后将数组z从高位z[num-1]到低位z[0]输出,就是Q进制数z。

搞不清楚的话,可以拿十进制数转换为二进制数作为参考。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
a = a+b;
int ans[31],num = 0;
do{
ans[num++] = a%d;
a /= d;
}while (a != 0);
for (int i=num-1;i>=0;i--){
printf("%d",ans[i]);
}
puts("");
return 0;
}

提一点,PAT的编译器,如果按照scanf的一般写法可能会警告,将scanf("%d",&t);改成if(scanf("%d",&t)){};就不会警告了。

坚持原创技术分享,您的支持将鼓励我继续创作!