目录
每日鸡汤:
🚀有志者自有千计万计,无志者只感千难万难。
🏆重新格式化电话号码
给你一个字符串形式的电话号码 number 。number 由数字、空格 ' '、和破折号 '-' 组成。
请你按下述方式重新格式化电话号码。
首先,删除 所有的空格和破折号。
其次,将数组从左到右 每 3 个一组 分块,直到 剩下 4 个或更少数字。剩下的数字将按下述规定再分块:
2 个数字:单个含 2 个数字的块。
3 个数字:单个含 3 个数字的块。
4 个数字:两个分别含 2 个数字的块。
最后用破折号将这些块连接起来。注意,重新格式化过程中 不应该 生成仅含 1 个数字的块,并且 最多 生成两个含 2 个数字的块。返回格式化后的电话号码。
通读一遍,要求很明确,每三个当作一组,然后破折号分开,当最后剩4个的时候,需要两两一组,少于4个的时候当作一组即可。
这道题目的解法也很普通,遍历一遍,设新的数组去存储这些数字字符。然后我们需要malloc一个新的数组当作最后的返回数组。平平无奇,但是我想说的是,如果这道题目不妥善处理,将会很麻烦。
👓①麻烦解法
如果不使用库函数去简化代码,将很辛苦,博主第一次做的时候就是暴力遍历数字字符数组,用两个变量计算两种情况需要多少个破折号;
1、第一种情况每三个数字字符为一组,用一个变量timesOf3记录有多少个破折号——,它记录的破折号用于隔离每三个数字字符,但是这里有个细节:
timesOf2记录当剩余小于等于4个字符时需要多少个破折号,比如剩余4个就需要2个破折号:
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&×Of3==0&×Of2==2)
||(count-i==2&×Of3==0&×Of2==1))
break;
if(time==3&×Of3>0)
{
number[m++]='-';
timesOf3--;
i--;
time=0;
}
else
{
number[m++]=tmp[i];
time++;
}
}
time=2;
while(i<count)
{
if(time==2&×Of2>0)
{
number[m++]='-';
timesOf2--;
time=0;
}
else
{
number[m++]=tmp[i++];
time++;
}
}
}
number[m]='\0';
return number;
}
时间复杂度:O(n)
空间复杂度:O(n)
👓②使用库函数降维打击
1、这道题目如果去使用库函数strncpy
是非常契合题目的。它可以拷贝指定大小的内容到目标空间。非常好用。这里还使用了一个库函数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题,能使用库函数去简化,我们尽量调用库函数,也能增进我们对库函数的掌握。如果不知道用什么库函数,就看一下答案,学习优秀代码咯🚀。