刚开始摸爬打滚的登上了求职的路上,经历了无数的面试以及笔试。至今还没有着落。经验已经积累了一些,今天在这里写详细分析一下我在笔试当中遇到的一个高频考题。没错,就是本章的题目,字符串的搜索以及替换。
目前参过4个不同公司企业的笔试了。其中这一题居然连续出现了两次。这一题比较考基础以及程序员的思维。看似简单但暗藏的玄机,如果不在考试之前做好充分的准备,那么在半个小时或一个小时以内把代码解出来,还是有相当的难度的。
其中有一家公司的考题我保留了下来,这道题是这样描述的:
A,B,C是3个字符串。把A中包含的所有B都替换为C,如果替换以后还有B就继续替换,直到A不包含B为止。
本题有三个字符串,由于字符串的大小以及内容并不是本题考点关键,所以我们一开始就可以很轻松的定义和赋值给这三个字符串。假如,
A[1000]=“abcdefghijklmn”;
B[100]=“cdef”;
C[100]=“zz”;
创建完之后,我们直接调用一个自己编写的函数,"“replace”,来完成题目的要求以及输出结果即可。
以上主要是main函数里的代码的解释。
具体代码如下:
int main(){
char A[1000], B[100], C[100];
printf("input A:");
fgets(A,1000,stdin);
printf("input B:");
fgets(B,100,stdin);
printf("input C:");
fgets(C,100,stdin);
printf("output A:");
printf("%s",replace(A,B,C));
return 0;
}
首先Replace函数是一个指针函数,这里需要重复指针函数的定义就是它是一个返回指针的函数,所以它的定义是这样的:
```c
char *replace(char *A, const char *B, const char *C);
这里之所以会把replace定义成一个指针函数,主要是为了方便上文中在main函数里的输出可以直接调用replace函数。这个函数里的参数分别为三个指针,就是这三个数组首位字母的地址。而其中B和C的类型为const目的主要是防止B和C的内容被修改。而A的内容是必须要被替换掉的,所以它的类型不可以是const。
A 是需要被修改的字符串,我们需要对这个字符串进行扫描,找出其中与B一样的部分,然后把这一个部分给替换成C。为了更好的理解,图一显示了整个代码的大概步骤。
第一步扫描就是把字符串从头到为都观察一遍。至于观察到什么时候为止呢?正常来说直接在for循环里面i++一直执行到i小于strlen(A)【A的大小】就可以了。不过在这道题里面,这样做会有一个问题。
观察一下上图,第四步里由于B和C的尺寸不一样,当C替代B之后,A的尺寸也发生了改变。所以A在这个函数里面尺寸是一直在变化的,所以这个办法不行。
通常会用的是第二个方法,当读到结束字符时停止。结束字符可以从上图看出来就是‘\0’。这个属于字符串的基础,暂时先不多加解释。
所以目前为止,我们的代码是:
```c
#include
#include
#include
char *replace(char *A, const char *B, const char *C){
int i;
for(i=0;*(A+i)!='\0';i++){
...
...
...
}
return A;
}
int main(){
char A[1000], B[100], C[100];
printf("input A:");
fgets(A,1000,stdin);
printf("input B:");
fgets(B,100,stdin);
printf("input C:");
fgets(C,100,stdin);
printf("output A:");
printf("%s",replace(A,B,C));
return 0;
}
字符串的搜索主要是找出A里面的B部分。刚才已经提到过以上扫描的概念了,而搜索又恰恰发生在扫描之下。大致思想就是,扫描A时,当扫到一个字符与字符串B第一个字符一样时,就会开始检测这个字之后的字符是否跟字符串B其余字符一致。一直检测到不一致为止。此过程中会有一个计数器。若计数器与字符串B的长度一直【count=strlen(B)-1】,则表示搜索成功。过程大致如下图:
#include
#include
#include
char *replace(char *A, const char *B, const char *C){
int i;
for(i=0;*(A+i)!='\0';i++){//扫描
int count;
for(count=0;*(A+i+count)==*(B+count);count++){};//检测
if(count==strlen(B)-1){ //搜索成功
}
}
return A;
}
int main(){
char A[1000], B[100], C[100];
printf("input A:");
fgets(A,1000,stdin);
printf("input B:");
fgets(B,100,stdin);
printf("input C:");
fgets(C,100,stdin);
printf("output A:");
printf("%s",replace(A,B,C));
return 0;
}
当发现A部分里的B后,我们不能马上把C替换掉B。原因在之前提及过,B和C的长度不一定相等。在本题假设中,若直接替代会发生如下情况:
在这个过程中,若直接进行位替代的话,我们会发现原本应该被覆盖掉的‘e’还存在在字符串里。如果在B长度小于C这种情况,还会导致原内容被篡改,这是一个更加严重问题。
为了解决这个问题,我在这里用到了一个比较笨拙的办法,叫做字符串备份。大致思路如下:
如图所示,我们会定义一个新的数组D,来记录被替代的B之后的部分,这样做可以避免了若B长度小于C而导致内容被覆盖的问题。
所以代码目前为止是这样的:
#include
#include
#include
char *replace(char *A, const char *B, const char *C){
int i;
for(i=0;*(A+i)!='\0';i++){ //扫描
int count,k;
for(count=0;*(A+i+count)==*(B+count);count++){}; //检测
if(count==strlen(B)-1){ //搜索成功
for(k=0;*(A+i+strlen(B)-1+k)!='\0';k++){
*(D+k)=*(A+i+strlen(B)-1+k); //备份后续字符串
*(A+i+strlen(B)-1+k)=0; //清空
}
*(A+i+strlen(B)-1+k)=0; //清空末尾
}
}
return A;
}
int main(){
char A[1000], B[100], C[100];
printf("input A:");
fgets(A,1000,stdin);
printf("input B:");
fgets(B,100,stdin);
printf("input C:");
fgets(C,100,stdin);
printf("output A:");
printf("%s",replace(A,B,C));
return 0;
}
终于都到了实现本题关键也是最容易的环节了——字符串替代。在这,我们直接修改A字符串内关于B的信息就可以了。详细内容如下图所示:
由于刚才做了字符串的备份,替代完之后,字符串后面的部分都为空,为了能够继续扫描下去,必须把后续的字符串给复原。这一步骤与字符串的替代相似,详细过程也如下图所示:
所以,最终的代码为:
#include
#include
#include
char *replace(char *A, const char *B, const char *C){
int i,j;
for(i=0;*(A+i)!='\0';i++){
int count=0,k=0,l=0;
char *D=(char*)malloc(1000*sizeof(char));
for(count=0;*(A+i+count)==*(B+count);count++){};
if(count==strlen(B)-1){ //搜索成功
for(k=0;*(A+i+strlen(B)-1+k)!='\0';k++){
*(D+k)=*(A+i+strlen(B)-1+k); //复制后续字符串,为位移做准备
*(A+i+strlen(B)-1+k)=0; //清空
}
*(A+i+strlen(B)-1+k)=0; //
for(j=0;j<strlen(C)-1;j++){
*(A+i+j)=*(C+j); //插入字符
}
for(l=0;l<strlen(D)-1;l++){
*(A+i+j+l)=*(D+l); //添加后续字符
}
*(A+i+j+l)='\0';
i=i+j-1;
}
}
return A;
}
int main(){
char A[1000], B[100], C[100];
printf("input A:");
fgets(A,1000,stdin);
printf("input B:");
fgets(B,100,stdin);
printf("input C:");
fgets(C,100,stdin);
printf("output A:");
printf("%s",replace(A,B,C));
return 0;
}
题主这个办法其实实在笨拙,而且对于熟悉掌握字符串内位于位直接的关系特别讲究。其实还有很多其余的方法,例如利用string.h里就有很多可用的函数库了。以后有机会的话定会再更新。
谢谢。