题解
身份证号码
1 条题解
-
0
解题思路
身份证号码一共有18位,其中藏着出生年月日:第7位到第14位是"年年月月日日",也就是年占4位、月占2位、日占2位。因为字符串的下标从0开始数,所以:
- 年份是
s[6]~s[9](第7~10个字符); - 月份是
s[10]~s[11](第11~12个字符); - 日期是
s[12]~s[13](第13~14个字符)。
我们要做两件事:
第一,把这三个部分从"字符"变成"整数"。 比如
s[10]='0'、s[11]='5',那月份就是0×10+5=5。用循环一位一位地拼:y=y*10+(s[i]-'0')。这里的s[i]-'0'是把字符数字变成真正的数字('0'减'0'等于0,'5'减'0'等于5)。第二,检查这个日期合不合法:
- 年份不能是0;
- 月份必须是1~12之间的数;
- 日期必须在这个月的天数范围之内。这里有个小陷阱:2月的天数不固定,闰年是29天,平年是28天。
- 闰年的判断口诀:能被4整除,但不能被100整除;或者能被400整除。比如2000年是闰年,1900年不是闰年。
如果年月日都合法,就输出"年 月 日";只要有一项不合法,就输出
error。参考代码
// 身份证号码:检查18位身份证中的出生年月日是否合法,合法则输出年月日 #include <iostream> #include <string> using namespace std; int md[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; // 每月的天数 bool leap(int y){ // 判断闰年 return (y%4==0&&y%100!=0)||y%400==0; } int main(){ string s; cin>>s; if(s.size()!=18){ cout<<"error"<<'\n'; return 0; } // 不是18位直接判错 // 第7~10位是年,第11~12位是月,第13~14位是日(下标从0开始) int y=0,m=0,d=0; for(int i=6;i<=9;i++) y=y*10+(s[i]-'0'); for(int i=10;i<=11;i++) m=m*10+(s[i]-'0'); for(int i=12;i<=13;i++) d=d*10+(s[i]-'0'); if(y<1){ cout<<"error"<<'\n'; return 0; } // 年份不能是0 if(m<1||m>12){ cout<<"error"<<'\n'; return 0; } // 月份必须在1~12之间 int maxd=md[m]; if(m==2&&leap(y)) maxd=29; // 闰年2月有29天 if(d<1||d>maxd){ cout<<"error"<<'\n'; return 0; } // 日期必须在当月天数内 cout<<y<<" "<<m<<" "<<d<<'\n'; return 0; }复杂度分析
- 时间复杂度:O(1)。身份证号码固定18位,我们只处理这18个字符,循环的次数是固定的,和输入是什么无关,属于"常数时间"。
- 空间复杂度:O(1),只需要一个字符串和几个整数变量,没有用到和输入规模有关的存储。
- 年份是
- 1