top1编程
← 返回题目
题解

身份证号码

1 条题解

  • 0
    @ 2026-8-5 10:29:40

    解题思路

    身份证号码一共有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)。

    第二,检查这个日期合不合法:

    1. 年份不能是0;
    2. 月份必须是1~12之间的数;
    3. 日期必须在这个月的天数范围之内。这里有个小陷阱:2月的天数不固定,闰年是29天,平年是28天。
    4. 闰年的判断口诀:能被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