欢迎光临
我们一直在努力

回文日期详细解析(新手向枚举题)

题目:

链接:https://ac.nowcoder.com/acm/problem/16438 来源:牛客网  

题意:

简单明了的说下题目意思,给你一个开始日期和一个结束日期,然后你需要在这个期间内计算有多少个满足回文日期的条件的(包括日期首尾),注意日期需要是合法的。

一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i个 数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

例如:

•对于2016年11月19日,用8位数字20161119表示,它不是回文的。

•对于2010年1月2日,用8位数字20100102表示,它是回文的。

•对于2010年10月2日,用8位数字20101002表示,它不是回文的。

回文判断

回文判断一般有俩种方式,一种纯数字,另一种是字符串类,这边主要给出纯数字的方式,这里比较方便。字符串类简单说说就是首尾一直对比到中间如果期间有不同则不为回文,反之则为回文。

而纯数字就是将一个数倒过来也就是最高位从末尾开始看起。

下边给出回文判断函数代码


bool huiwen(int num)
{
int rev=0;//定义一个装倒置的数
int t=num;//接下来num会变化为了最后比较倒置与原本的数是否相等用t记录原本的num
while(num>0)
{
rev=rev*10+num%10;//这边操作看起来就像是把num从个位开始一个个传给rev的末尾上
num/=10;
}
if(rev==t)return 1;//比较
return 0;
}

这边还可以再优化一下其实这里的回文日期只需比较前四位后和后四位就行,因为它是对称的的嘛


日期合法性

第一次做这个题很容易漏的一个点,我们在枚举过程中需要对日期合法性进行判断再进行回文的判断,俩者都满足时才可进行回文日期的计数。

下边给出日期合法性判断函数代码

int monday[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//平年的每月天数
int mondayleap[]={0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年的每月天数
bool isleapyear(int num)//还要注意闰年会影响日期合法性的判断
{
if(num%400==0||num%4==0&&num%100!=0)//闰年判断
{
return 1;
}
return 0;
}
bool islegal(int y,int m,int d)//y代表year,m代表month,d代表day。
{
if(isleapyear(y)&&m>=1&&m<=12)
{
if(d>=1&&d<=mondayleap[m])
return 1;
}
else if(!isleapyear(y)&&m>=1&&m<=12)
{
if(d>=1&&d<=monday[m])
return 1;
}
return 0;
}//根据月份的范围和不同月的天数进行判断

提一嘴,这个不同月代表的天数的日期数组为什么要开俩个?其实我早期做这题的时候就因为这个事卡了好久,你只有一个数组你还要改变2月份的天数很容易乱,这样俩个数组的方式更加清晰方便


接下来完整ac代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int monday[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//平年的每月天数
int mondayleap[]={0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年的每月天数
bool isleapyear(int num)//还要注意闰年会影响日期合法性的判断
{
if(num%400==0||num%4==0&&num%100!=0)//闰年判断
{
return 1;
}
return 0;
}
bool huiwen(int num)
{
int rev=0;//定义一个装倒置的数
int t=num;//接下来num会变化为了最后比较倒置与原本的数是否相等用t记录原本的num
while(num>0)
{
rev=rev*10+num%10;//这边操作看起来就像是把num从个位开始一个个传给rev的末尾上
num/=10;
}
if(rev==t)return 1;//比较
return 0;
}
bool islegal(int y,int m,int d)//y代表year,m代表month,d代表day。
{
if(isleapyear(y)&&m>=1&&m<=12)
{
if(d>=1&&d<=mondayleap[m])
return 1;
}
else if(!isleapyear(y)&&m>=1&&m<=12)
{
if(d>=1&&d<=monday[m])
return 1;
}
return 0;
}//根据月份的范围和不同月的天数进行判断
signed main()
{
int cnt=0;
int start;
int end;
cin >> start >> end;
for(int i=start;i<=end;i++)
{
int y=i/10000;
int m=i%10000/100;
int d=i%100;
if(!islegal(y,m,d))continue;
if(huiwen(i))cnt++;
}
cout << cnt;
return 0;
}


因为日期数是八位数所以我这里开了个long long保险了一波,但如果题目给的数位过大long long也救不了。

总结

  • 这题主要需要会的点有三个
  • 第一,回文数的判断方法
  • 第二,日期合法性的判断
  • 第三,闰年判断

第一次做这题的时候感觉思路很乱代码很乱,但现在看来感觉清晰非常多,看来多做题培养代码逻辑思维还是相当有用的。

赞(0)
未经允许不得转载:171主机测评 » 回文日期详细解析(新手向枚举题)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址