一些C語言中字串的演算法問題解決執行個體小結_C 語言

來源:互聯網
上載者:User

    字串問題是面試中經常出現的問題,這類問題有很多,難以不一。下面是幾道字串的題目,網上都能找到解答,自己實現了一下,供網友參考。感覺演算法重要的是要有正確的思路,實現起來不是問題。自己一定要多思考,這樣收穫可能會更多一點。
       
問題1:找兩個字串的最長公用子串。
        具體描述,如果字串一的所有字元按其在字串中的順序出現在另外一個字串二中,則字串一稱之為字串二的子串。注意,並不要求子串(字串一)的字元必須連續出現在字串二中。請編寫一個函數,輸入兩個字串,求它們的最長公用子串,並列印出最長公用子串。
    思路:演算法書上一般都有介紹,就是用動態規劃的思想。關鍵是要找到最優子結構性質,這一點比較難。另外一個經常問到的問題“求子數組的最大和”,用的也是動態規劃的思想。找兩個字串最長公用子串的核心就是找最優子結構。
        設序列X = {x1,x2,…xm}和Y = {y1,y2,…yn}的最長公用子串為Z = {z1,z2,…zk},則
        1 若xm= yn且zk=xm=yn, 則Zk-1是Xm-1和Yn-1的最長公用子串
        2 若xm!=yn且zk!=xm,則Z是Xm-1和Y的最長公用子串
        3 若xm!=yn且zk!=yn,則Z是X和Yn-1的最長公用子串
         其中Xm-1= {x1,x2,…,xm-1},Yn-1 = {y1,y2,…,yn-1}Zk-1 = {z1,z2,…zk-1}
      有了上述關係,則很容易得到遞推的式子。用一個二維數組 R 記錄結果,其中Z[i][j]表示Xi和Yj的最長公用子串長度。
     (1)如果i = 0或j = 0,Z[i][j] = 0
     (2)如果xi和yj相等,Z[i][j] = Z[i-1][j-1] + 1
     (3) 如果xi和yj不相等,Z[i][j] = max{Z[i-1][j],Z[i][j-1]}
        基本上差不多了,但是題目要求列印最長公用子串,只要用一個數組R記錄得到最長公用子串的過程,其中R[i][j]表示Z[i][j]的值是由哪個子問題的解得到的。
       參考代碼:

//函數功能 : 列印最長公用子串 //函數參數 : X為源字串1,Y為源字串2,R為記錄的過程,row為R的行座標,col為R的列座標 //傳回值 :  空 void LCS_Print(const char *X, const char *Y, int **R, int row, int col) {   if(R[row][col] == 1)   {     LCS_Print(X, Y, R, row-1, col-1);     cout<<X[row-1];  //由Xi-1和Yj-1,再加上Xi或Yj得到   }   else if(R[row][col] == 2)     LCS_Print(X, Y, R, row-1, col); //由Xi-1和Yj得到   else if(R[row][col] == 3)      LCS_Print(X, Y, R, row, col-1); //由Xi和Yj-1得到   else     return; } //函數功能 : 求兩個字串的最大公用子串 //函數參數 : X為源字串1,Y為源字串2 //傳回值 :  最大長度 int LCS(const char *X,const char *Y) {   if(X == NULL || Y == NULL)     return 0;    int lenX = strlen(X);   int lenY = strlen(Y);   if(lenX == 0 || lenY == 0)     return 0;    int i, j;   int **C = new int *[lenX+1];   int **R = new int *[lenX+1];    //初始化   for(i = 0; i <= lenX; i++)   {     C[i] = new int [lenY+1];     R[i] = new int [lenY+1];     for(j = 0; j <= lenY; j++)     {       C[i][j] = 0;       R[i][j] = 0;     }   }    //開始計算    for(i = 1; i <=lenX; i++)   {     for(j = 1; j <=lenY; j++)     {       if(X[i-1] == Y[j-1]) //字串的下標從0開始,所以減1,即X1 = X[0] Y1 = Y[0]       {         C[i][j] = C[i-1][j-1] + 1;         R[i][j] = 1;  //由Xi-1和Yj-1,再加上Xi或Yj得到       }       else       {         if(C[i-1][j] >= C[i][j-1])          {           C[i][j] = C[i-1][j];           R[i][j] = 2;   //由Xi-1和Yj得到         }         else          {           C[i][j] = C[i][j-1];           R[i][j] = 3;   //由Xi和Yj-1得到         }       }     }   }   //列印最長公用子串   LCS_Print(X, Y, R, lenX, lenY);   //記錄最大長度   int lcs = C[lenX][lenY];     //釋放空間   for(i = 0; i <= lenX; i++)   {     delete [] C[i];     delete [] R[i];   }   delete C;   delete R;   R = C = NULL;   return lcs; } 

      
問題2:在字串中刪除特定元素
    具體描述,輸入兩個字串,從第一字串中刪除第二個字串中所有的字元。例如,輸入”They are students.”和”aeiou”,則刪除之後的第一個字串變成”Thy r stdnts.”。
    思路:這是字元尋找的一個問題,最簡單的就是考察第二個字串的每個字元,然後檢查第一個字串中有沒有這個字元,有的話刪除。這樣的時間複雜度是O(mn)。對於尋找,我們容易想到二分尋找、散列這些概念。散列的尋找是非常快,時間複雜度為O(1)。如果能聯想到散列,那麼很容易就能給出下面的解法,相信很多人都能想到。需要一個256位元組的數組,記錄第二個字串中每個字元的出現情況,0表示未出現,1表示出現。然後遍曆第一個字串,針對每個字元,去查詢記錄數組,以決定刪除與否。
   參考代碼:

//函數功能 : 在字串中刪除特定字元 //函數參數 : pSrc為源字串,pDel為特定字元集 //傳回值 :  空 void DeleteSpecialChars(char *pSrc, char *pDel) {   if(pSrc == NULL || pDel == NULL)     return;   int lenSrc = strlen(pSrc);   int lenDel = strlen(pDel);   if(lenSrc == 0 || lenDel == 0)     return;   bool hash[256] = { false };   for(int i = 0; i < lenDel; i++) //建立刪除字元的索引     hash[pDel[i]] = true;   //開始刪除   char *pCur = pSrc;   while(*pSrc != '\0')   {     if(hash[*pSrc] == false) //不用刪除       *pCur++ = *pSrc;     pSrc++;   }   *pCur = '\0'; }

問題3:左旋轉字串,其實也可以左旋數組
   具體描述,定義字串的左旋轉操作:把字串前面的若干個字元移動到字串的尾部。如把字串abcdef左旋轉2位得到字串cdefab。請實現字串左旋轉的函數。要求時間對長度為n的字串操作的複雜度為O(n),輔助記憶體為O(1)。
   思路:用了一個小技巧,如果旋轉的字串為XY,其中Y是要旋轉到X前面的。只要分別將子字串 X 和 Y 翻轉,然後再將整個字串再做一次翻轉即可。STL的一個演算法rotate就是用了這個。
   參考代碼:

//函數功能 : 將字串翻轉 //函數參數 : pBegin指向第一個字元,pEnd指向最後一個字元 //傳回值 :  空 void ReverseString(char *pBegin, char *pEnd) {   if(pBegin == NULL || pEnd == NULL)     return;    while(pBegin < pEnd)   {     //交換字元     char tmp = *pBegin;     *pBegin = *pEnd;     *pEnd = tmp;     //往中間靠攏     pBegin++;     pEnd--;   } }  //函數功能 : 將字串左旋 n 位 //函數參數 : pSrc為源字串,n為左旋位元 //傳回值 :  空 void LeftRotateString(char *pSrc, unsigned n) {   if(pSrc == NULL || n == 0 || n > strlen(pSrc))     return;    int len = strlen(pSrc);   ReverseString(pSrc, pSrc + n - 1);   ReverseString(pSrc + n, pSrc + len - 1);   ReverseString(pSrc, pSrc + len - 1); } 

  
問題4:在一個字串中找到第一個只出現一次的字元。如輸入abaccdeff,則輸出b。
   思路:這一題不難,因為每個字元只有8位,因此可以用計數法。首先統計字串中每個字元的出現次數,然後從頭遍曆字串,對於當前字元,查詢統計表,如果出現的次數為1,則輸出該字元即可。
   參考代碼:

//函數功能 : 在一個字串中找到第一個只出現一次的字元 //函數參數 : pStr為源字串 //傳回值 :  目標字元 char FirstAppearOnce(char *pStr) {   if(pStr == NULL)     return '\0'; //未找到返回Null 字元    int count[256] = {0};   char *pTmp = pStr;      while(*pTmp != '\0') //統計字串中每個字元出現的次數   {     count[*pTmp]++;     pTmp++;   }   while(*pStr != '\0') //遍曆字串,找到第一個只出現一次的字元   {     if(count[*pStr] == 1)       break;     pStr++;   }   return *pStr; //找到的字元 } 

      
問題5:寫一個函數,它的原形是int continumax(char *outputstr,char *intputstr)。功能:在字串中找出連續最長的數字串,並把這個串的長度返回,並把這個最長數字串付給其中一個函數參數outputstr所指記憶體。
        例如:"abcd12345ed125ss123456789"的首地址傳給intputstr後,函數將返回9,outputstr所指的值為123456789
    思路:這一題比較簡單,掃描一遍字串即可,遇到數字時將數字個數加1,然後與最長串比較,如果長度大於最長串,更新最長串;遇到非數字時,將數字計數器清零。
    參考代碼:函數名和形參名修改了一下,個人習慣。

//函數功能 : 在字串中找出連續最長的數字串 //函數參數 : pSrc表示源串,pDest記錄最長數字串的起始位置 //傳回值 :  最長數字串的長度 int ContinueMax(char *pSrc,char * &pDest) {   pDest = NULL;   if(pSrc == NULL)     return 0;    int max = 0, cnt = 0;   while(*pSrc != '\0')   {     if(*pSrc >= '0' && *pSrc <= '9') //數字     {       cnt++;       if(cnt > max) //更新最長的數字串       {         pDest = pSrc - cnt + 1;         max = cnt;       }     }     else       cnt = 0;     pSrc++;   }   if(cnt > max)   {     pDest = pSrc - cnt + 1;     max = cnt;   }   return max; } 

問題6:字串轉換為整數
      問題描述:輸入一個表示整數的字串,把該字串轉換成整數並輸出。例如輸入字串"345",則輸出整數345。
       思路:轉換的過程比較簡單,每次讀入一個字元,將之前儲存的值乘以10,然後再加上這個字元表示的數字。這是正常情況。這個問題主要是考察各種不正常情況的處理。假設函數的聲明為 int StrToInt(const char *str);
       (1)輸入的字串指標為空白;
       (2)數字前面有加號或減號的處理;
       (3)字串表示的數字超過了32位整數能表示的範圍,即溢出處理;
       (4)輸入了非法字元,即除了數字及加號或減號的其他字元;
       (5)以字元' 0 '開始的串,' 0 '後面還跟了其他字元,也是非法的。
        如果能很好的處理這些情況,那麼程式的健壯性大大增強。其中有兩種情況處理起來有點麻煩,第一,如何處理溢出,我們可以使用std::numeric_limits<int>::max(),可以定義一個long long的變數,然後與這個最大值相比,從而判斷是否溢出了。第二。由於傳回值為一個整型數,那麼如果轉換失敗,返回什麼呢?如果是'0 ' ,那麼就無法區分正常輸入"0"的情況。兩種方案,修改函式宣告,通過傳回值表明轉換的成功與否,或者定義一個全域變數,用來儲存轉換的成功與否。參考代碼中使用了第二種方案。
        參考代碼:先給出的是std::numeric_limits<int>::max()的用法。

#include <iostream> #include <limits>  //需包含這個標頭檔 using namespace std; int main() {   cout << "The maximum value for type float is: "     << numeric_limits<float>::max( )     << endl;   cout << "The maximum value for type double is: "     << numeric_limits<double>::max( )     << endl;   cout << "The maximum value for type int is: "     << numeric_limits<int>::max( )     << endl;   cout << "The maximum value for type short int is: "     << numeric_limits<short int>::max( )     << endl; }       bool strToIntOK; //全域的變數  int StrToInt(const char *str)  {    strToIntOK = false;    if(str == NULL) //null 指標      return 0;        if(str[0] == '0' && str[1] != '\0') //以'0'開始但不是"0" 這條其實可以忽略      return 0;        unsigned i = 0;    bool minus = false;  //負數標記    if(str[i] == '-' || str[i] == '+') //判斷是不是以加號或減號開始    {      minus = (str[i] == '-')? true: false;      i++;    }        long long result = 0; //轉換的結果    while(str[i] != '\0')    {      char c = str[i++];      if(c >= '0' && c <='9')      {        result = result * 10 + (c - '0');        if(minus) //負溢出       {         if(result - 1 > numeric_limits<int>::max())            return 0;        }       else //正溢出       {         if(result > numeric_limits<int>::max())           return 0;        }     }      else      {        return 0;      }    }    strToIntOK = true;    //結果返回 需強制轉換一下    return minus? (int)(-result):(int)result;  }  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.