leetcode每日一题

简介: leetcode每日一题

🏆重新格式化电话号码


给你一个字符串形式的电话号码 number 。number 由数字、空格 ' '、和破折号 '-' 组成。


请你按下述方式重新格式化电话号码。


首先,删除 所有的空格和破折号。

其次,将数组从左到右 每 3 个一组 分块,直到 剩下 4 个或更少数字。剩下的数字将按下述规定再分块:

2 个数字:单个含 2 个数字的块。

3 个数字:单个含 3 个数字的块。

4 个数字:两个分别含 2 个数字的块。

最后用破折号将这些块连接起来。注意,重新格式化过程中 不应该 生成仅含 1 个数字的块,并且 最多 生成两个含 2 个数字的块。


返回格式化后的电话号码。


1669267627754.jpg


通读一遍,要求很明确,每三个当作一组,然后破折号分开,当最后剩4个的时候,需要两两一组,少于4个的时候当作一组即可。


这道题目的解法也很普通,遍历一遍,设新的数组去存储这些数字字符。然后我们需要malloc一个新的数组当作最后的返回数组。平平无奇,但是我想说的是,如果这道题目不妥善处理,将会很麻烦。


👓①麻烦解法


如果不使用库函数去简化代码,将很辛苦,博主第一次做的时候就是暴力遍历数字字符数组,用两个变量计算两种情况需要多少个破折号;


1、第一种情况每三个数字字符为一组,用一个变量timesOf3记录有多少个破折号——,它记录的破折号用于隔离每三个数字字符,但是这里有个细节:


1669267642370.jpg


timesOf2记录当剩余小于等于4个字符时需要多少个破折号,比如剩余4个就需要2个破折号:

1669267650265.jpg

2、比较麻烦的是,我并没有使用库函数去简化代码,而是用创建变量标记,记录当每遍历到3个时,就在循环里特殊处理一下加一下‘——’。然后还需要考虑特殊情况,非常麻烦。


说明:可能有的老铁觉得为什么要计算破折号的个数,直接作减去做这道题目不是舒服点嘛,我给老铁说明一下,直接作减确实比较方便,但是我们不知道要返回的数字字符数组多大空间啊,博主主要想通过计算破折号加上原有长度(当然别忘记'\0'),就能精确计算到底需要多少空间,不至于空间浪费。(但事实证明大部分oj题给大点空间(一般两倍)都可以通过,有点没必要浪费代码去做这个工作😂)


char * reformatNumber(char * number)
{
    int length=strlen(number);
    char tmp[length];
    int count=0;
    for(int i=0;i<length;++i)
    {
        if(number[i]!='-'&&number[i]!=' ')
            tmp[count++]=number[i];
    }
    //计算需要多少破折号
    int m=0;
    if(count==4)
    {
        char* ret=(char*)realloc(number,sizeof(char)*7);
        if(ret==NULL)
        {
            perror("realloc fail");
            exit(-1);
        }
        number=ret;
        int time=0;
        for(int i=0;i<count;++i)
        {
            if(time==2)
            {
                number[m++]='-';
                i--;
                time=0;
            }
            else
            {
                number[m++]=tmp[i];
                time++;
            }
        }
    }
    else
    {
        int timesOf3=count/3;//这里其实多了一个,后面剪去
        int timesOf2=0;
        if(count-timesOf3*3==1)
        {
            //说明剩余了4
            timesOf3-=2;//需要少一个
            timesOf2=2;
        }
        else if(count-timesOf3*3==2)
        {
            timesOf3-=1;
            timesOf2=1;
        }
        else
        {
            timesOf3-=1;
        }
        char* ret=(char*)realloc(number,sizeof(char)*(timesOf3+timesOf2+count+1));
        if(ret==NULL)
        {
            perror("realloc fail");
            exit(-1);
        }
        number=ret;
        int time=0;
        int i=0;
        for(i=0;i<count;++i)
        {
            if((count-i==4&&timesOf3==0&&timesOf2==2)
            ||(count-i==2&&timesOf3==0&&timesOf2==1))
                break;
            if(time==3&&timesOf3>0)
            {
                number[m++]='-';
                timesOf3--;
                i--;
                time=0;
            }
            else
            {
                number[m++]=tmp[i];
                time++;
            }
        }
        time=2;
        while(i<count)
        {
            if(time==2&&timesOf2>0)
            {
                number[m++]='-';
                timesOf2--;
                time=0;
            }
            else
            {
                number[m++]=tmp[i++];
                time++;
            }
        }
        }
     number[m]='\0';
     return number;
}

时间复杂度:O(n)

空间复杂度:O(n)


👓②使用库函数降维打击


1、这道题目如果去使用库函数strncpy


1669267678984.jpg


是非常契合题目的。它可以拷贝指定大小的内容到目标空间。非常好用。这里还使用了一个库函数isdigit---int isdigit(int c) 检查所传的字符是否是十进制数字字符。


2、还可以简化的地方是,不要去计算3个为一组需要多少个破折号,剩余的小于等于四个数字字符需要多少个破折号。而是不断作减法,每拷贝3个数字字符,数字字符个数减3,加破折号,当小于等于4个时就特别处理一下。


char * reformatNumber(char * number)
{
    int length=strlen(number);
    char digits[length+1];
    int pos=0;
    for(int i=0;i<length;++i)
    {
        char ch=number[i];
        if(isdigit(ch))
        {
            //是数字字符就存下来
            digits[pos++]=ch;
        }
    }
    int n=pos;//存一下数字字符个数
    //开辟空间--比较粗暴,其实可以计算
    char *ret=(char*)malloc(sizeof(char)*n*2);
    pos=0;
    int pt=0;
    while(n)
    {
        if(n>4)
        {
            strncpy(ret+pos,digits+pt,3);
            pos+=3;
            ret[pos++]='-';
            pt+=3;
            n-=3;
        }
        else
        {
            if(n==4)
            {
                strncpy(ret+pos,digits+pt,2);
                pos+=2;
                ret[pos++]='-';
                pt+=2;
                strncpy(ret+pos,digits+pt,2);
                pos+=2;
            }
            else
            {
                strncpy(ret+pos,digits+pt,n);
                pos+=n;
            }
            break;
        }
    }
    ret[pos]='\0';
    return ret;
}


时间复杂度:O(N)


空间复杂度:O(N)


这道题目,其实并不难,只是提醒我们在做oj题,能使用库函数去简化,我们尽量调用库函数,也能增进我们对库函数的掌握。如果不知道用什么库函数,就看一下答案,学习优秀代码咯🚀。

目录
打赏
0
0
0
0
2
分享
相关文章
数据库数据恢复——MongoDB数据库服务无法启动的数据恢复案例
MongoDB数据库数据恢复环境: 一台Windows Server操作系统虚拟机上部署MongoDB数据库。 MongoDB数据库故障: 管理员在未关闭MongoDB服务的情况下拷贝数据库文件。将MongoDB数据库文件拷贝到其他分区后,对MongoDB数据库所在原分区进行了格式化操作。格式化完成后将数据库文件拷回原分区,并重新启动MongoDB服务。发现服务无法启动并报错。
公网使用SSH远程连接安卓手机Termux - Android手机服务器
使用安卓机跑东西的时候,屏幕太小,有时候操作不习惯。不过我们可以开启ssh,使用电脑PC端SSH远程连接手机termux。 本次教程主要实现在安卓手机termux上安装SSH,在电脑上通过SSH远程连接Termux。同时在Termux上做内网穿透,用cpolar创建安全隧道映射22端口,实现在外也可以SSH远程连接Termux,无需公网IP,也不用设置路由器 ,这里使用国产内网穿透工具cpolar简单实现。
云存储Clouder认证:基于存储产品快速搭建网盘—课时7:基于对象存储OSS快速搭建网盘
云存储Clouder认证:基于存储产品快速搭建网盘—课时7:基于对象存储OSS快速搭建网盘
大厂前端日常窥探「壹」:企业级软件开发流程长啥样?(下)
大厂前端日常窥探「壹」:企业级软件开发流程长啥样?
360 0
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(上)
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新
511 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等