数据结构与算法

数据结构与算法 - 两个指针搞定字符串操作

分类: 数据结构与算法 459人阅读 评论(0) 收藏 举报

在笔试、面试中经常出现对字符串的操作,所以对于字符串的常用操作要熟练掌握。同时也要牢固掌握字符串的基本操作。

在C语言中,可以通过如下的方式来声明字符串:

1、char *str="字符串";// 字符常量

2、char str[]="字符串";// 字符数组
   在C++中,可以使用string字符串类型,在Java中可以使用String。但是字符串类型最终都是转换为字符数组进行操作的,只是C++和Java对此做了进一步的封装。
C和C++系统提供的一些函数如下:
字符串的函数有:
(1)strlen()求长度
(2)strcmp()比较字符串的大小
(3)strcpy()字串复制函数  利用标准库函数strncpy(),可以将一字符串的一部分拷贝到另一个字符串中。strncpy()函数有3个参数:第一个参数是目标字符串;第二个参数是源字符串;第三个参数是一个整数,代表要从源字符串拷贝到目标字符串中的字符数
(4)char *strstr(char *str1, char *str2); 从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。

在笔试、面试中,常见到的字符串操作如下:
(1)字符串空格问题:如接收有空格的字符串、去除字符串中间的空格等
(2)字符串顺序:如反转字符串、左旋字符串
(3)求最长回文子串等
下面将详细讲解这几个问题。
1、去除字符串空格
删除字符串开始及末尾的空白符,并且把数组中间的多个空格(如果有)符转化为1个。

  1. # include <stdio.h>  
  2. # include <math.h>  
  3. void DelSpace(char *s){  
  4.     if(s == NULL)   return;  
  5.     int flag = 0 ;  
  6.     if(*s == ' ')   flag = 1;  
  7.     char *p = s;  
  8.     int j = 0;  
  9.     while(*p != '\0'){  
  10.         if(*p != ' ')  
  11.             s[j++] = *p;  
  12.         else{  
  13.             while(*p == ' '){  
  14.                             p++;  
  15.                         }    
  16.                         // 在首或尾的地方不需要再加入空格,p++可能导致这里的p指向'\0'  
  17.             if(flag==1 || *p=='\0'){  
  18.                  flag = 0;  
  19.             }else{  
  20.                              s[j++] = ' ';  
  21.                         }  
  22.             p--;//方便外层的p++做处理  
  23.         }  
  24.         p++;  
  25.     }  
  26.     s[j] = '\0';  
  27. }  
  28. int main(){  
  29.   char str[]="   dddd    psdf dd ";  
  30.   DelSpace(str);  
  31.   printf("%s",str);  
  32. }  
# include <stdio.h>
# include <math.h>
void DelSpace(char *s){
	if(s == NULL)	return;
	int flag = 0 ;
	if(*s == ' ')	flag = 1;
	char *p = s;
	int j = 0;
	while(*p != '\0'){
		if(*p != ' ')
			s[j++] = *p;
		else{
			while(*p == ' '){
                            p++;
                        }  
                        // 在首或尾的地方不需要再加入空格,p++可能导致这里的p指向'\0'
			if(flag==1 || *p=='\0'){
			     flag = 0;
			}else{
                             s[j++] = ' ';
                        }
			p--;//方便外层的p++做处理
		}
		p++;
	}
	s[j] = '\0';
}
int main(){
  char str[]="   dddd    psdf dd ";
  DelSpace(str);
  printf("%s",str);
}
在做如上的题目时,需要对指针进行判空操作,这样才体现出程序的健壮性。

2、左旋字符串

将一个字符串左边的n个字符移动到右边即左旋字符串。解决的思路非常多,但是有一个方法感觉比较好。首先想一下,如果要将一个字符串反转,你会怎么做?

(1)设两个指针,一个指向字符串开头start,一个指向字符串末尾end,然后交换指针的值。

(2)start加1,而end减1,直到start>=end为止。

代码如下:

  1. char * invert(char *start, char *end) {         
  2.     char tmp, *ptmp = start;          
  3.     while (start != NULL && end != NULL && start < end){         
  4.         tmp = *start;         
  5.         *start = *end;            
  6.         *end = tmp;           
  7.         start ++;         
  8.         end --;       
  9.     }      
  10.     return ptmp;      
  11. }    
char * invert(char *start, char *end) {       
    char tmp, *ptmp = start;        
    while (start != NULL && end != NULL && start < end){       
        tmp = *start;       
        *start = *end;          
        *end = tmp;         
        start ++;       
        end --;     
    }    
    return ptmp;    
}  

       下面来反转字符串。将一个字符串分成两部分,X和Y两个部分,在字符串上定义反转的操作X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么我们可以得到下面的结论:(X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。

不是么?ok,就拿abcdef 这个例子来说,若要让def翻转到abc的前头,那么只要按下述3个步骤操作即可:
1、首先分为俩部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。

如下图所示。


具体的实现代码如下:

  1.     
  2. char *left(char *s, int pos)   //pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。      
  3. {      
  4.     int len = strlen(s);      
  5.     invert(s, s + (pos - 1));  //如上,X->X^T,即 abc->cba      
  6.     invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed      
  7.     invert(s, s + (len - 1));  //如上,整个翻转,(X^TY^T)^T=YX,即 cbafed->defabc。      
  8.     return s;      
  9. }      
  
char *left(char *s, int pos)   //pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。    
{    
    int len = strlen(s);    
    invert(s, s + (pos - 1));  //如上,X->X^T,即 abc->cba    
    invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed    
    invert(s, s + (len - 1));  //如上,整个翻转,(X^TY^T)^T=YX,即 cbafed->defabc。    
    return s;    
}    

3、求最长回文子串

输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串连续出现的字符串片段。回文的含义是:正着看和倒着看是相同的,如abba和abbebba。输入字符串长度大于等于1小于等于5000。

    由于相同字母组成的一定是回文子串,如a,aa,aaaa,所以在遍历字符串字符时,直接找第i个元素(图中浅绿n)左右两边与该字符不相同的字符,并用两个指针pre和post指向。如下图。


    这样就可以将pre--,post++,然后比较*pre和*post的值。如果相等,继续pre--,post++(在操作时注意pre和post的边界条件);如果不相等,记录并更新回文子串的长度即可。

代码如下:

  1. #include <iostream>  
  2. #include <cstdio>  
  3.   
  4. using namespace std;  
  5. char *x;  
  6. int length=0;  
  7. void findCircle(char *str){  
  8.     if(str==NULL) return;  
  9.     char *pre=NULL,*post=NULL;  
  10.     for(str; *str!='\0'; str++){  
  11.         pre=str;post=str;  
  12.         while(*(post+1)!='\0'&&*(post+1)==*str) post++;  
  13.         while(*(pre-1)!='\0'&&*(pre-1)==*str)  pre--;  
  14.   
  15.         while( pre-1!=NULL&&post+1!=NULL&& (*(pre-1)==*(post+1))  ){  
  16.             pre=pre-1;  
  17.             post=post+1;  
  18.   
  19.         }  
  20.         if(post-pre+1>length) {  
  21.             length=post-pre+1;  
  22.             x=pre;  
  23.         }  
  24.     }  
  25.     for(int i=0;i<length;i++){  
  26.        cout<<*(x++)<<"  ";  
  27.     }  
  28. }  
  29.   
  30. int main(){  
  31.     char *str;  
  32.     gets(str);  
  33.     findCircle(str);  
  34.     return 0;  
  35. }  
#include <iostream>
#include <cstdio>

using namespace std;
char *x;
int length=0;
void findCircle(char *str){
    if(str==NULL) return;
    char *pre=NULL,*post=NULL;
    for(str; *str!='\0'; str++){
        pre=str;post=str;
        while(*(post+1)!='\0'&&*(post+1)==*str) post++;
        while(*(pre-1)!='\0'&&*(pre-1)==*str)  pre--;

        while( pre-1!=NULL&&post+1!=NULL&& (*(pre-1)==*(post+1))  ){
            pre=pre-1;
            post=post+1;

        }
        if(post-pre+1>length) {
            length=post-pre+1;
            x=pre;
        }
    }
    for(int i=0;i<length;i++){
       cout<<*(x++)<<"  ";
    }
}

int main(){
    char *str;
    gets(str);
    findCircle(str);
    return 0;
}


       常见的字符串操作非常多,但是如上几个题目有一个共同的特点:那就是使用两个指针就可以搞定这类型的题目。对于第一题和最后一题,是通过数组下标来标识位置的,我们也完全可以使用一个指针来标识,就像中间的两类型题目,使用一个指针来标识位置。所以只要指针操作过关,这类型的题目思路相对简单,解出来的难度不是很大。


参考博客July

2
0
发布了1 篇原创文章 · 获赞 9 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章