數據結構與算法

數據結構與算法 - 兩個指針搞定字符串操作

分類: 數據結構與算法 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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章