🏆重新格式化电话号码
给你一个字符串形式的电话号码 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题,能使用库函数去简化,我们尽量调用库函数,也能增进我们对库函数的掌握。如果不知道用什么库函数,就看一下答案,学习优秀代码咯🚀。