字符串轉換成整數,字符串匹配問題

本文轉自csdn大神v_JULY_v的博客

地址:

http://blog.csdn.net/v_july_v/article/details/9024123

閱讀心得:自己原先想得太天真了。。。



第三十~三十一章:字符串轉換成整數,字符串匹配問題


前言

    之前本一直想寫寫神經網絡算法和EM算法,但寫這兩個算法實在需要大段大段的時間,而平時上班,週末則跑去北大教室自習看書(順便以時間爲序,說下過去半年看過的自覺還不錯的幾本書:《數理統計學簡史》《微積分概念發展史》《微積分的歷程:從牛頓到勒貝格》《數學恩仇錄》《數學與知識的探求》《古今數學思想》《素數之戀》),故一直未曾有時間寫。

     然最近在負責一款在線編程挑戰平臺:http://hero.pongo.cn/簡稱hero,通俗理解是中國的topcoder,當然,一直在不斷完善中,與一般OJ不同點在於,OJ側重爲參與ACM競賽者提供刷題練習的場所,而hero則着重爲企業招聘面試服務),在上面出了幾道編程面試題,有些題目看似簡單,但一coding,很多問題便立馬都在hero上給暴露出來了,故就從hero上的編程挑戰題切入,繼續更新本程序員編程藝術系列吧。

    況且,前幾天與一朋友聊天,他說他認識的今年360招進來的三四十人應屆生包括他自己找工作時基本都看過我的博客,則更增加了更新此編程藝術系列的動力。

    OK,本文講兩個問題:

  • 第三十章、字符串轉換成整數;
  • 第三十一章、字符串匹配問題
    還是這句老話,有問題懇請隨時批評指正,感謝。


第三十章、字符串轉換成整數

    先看題目:

輸入一個表示整數的字符串,把該字符串轉換成整數並輸出,例如輸入字符串"345",則輸出整數345。
請完成函數StrToInt,實現字符串轉換成整數的功能,不得用庫函數atoi。

    我們來一步一步分析,直至寫出第一份準確的代碼:

1、本題考查的實際上就是字符串轉換成整數的問題,或者說是要你自行實現atoi函數。那如何實現把表示整數的字符串正確地轉換成整數呢?以"345"作爲例子:

  1. 當我們掃描到字符串的第一個字符'3'時,由於我們知道這是第一位,所以得到數字3。
  2. 當掃描到第二個數字'4'時,而之前我們知道前面有一個3,所以便在後面加上一個數字4,那前面的3相當於30,因此得到數字:3*10+4=34。
  3. 繼續掃描到字符'5','5'的前面已經有了34,由於前面的34相當於340,加上後面掃描到的5,最終得到的數是:34*10+5=345。

    因此,此題的思路便是:每掃描到一個字符,我們便把在之前得到的數字乘以10,然後再加上當前字符表示的數字。

    2、思路有了,有一些細節需要注意,如zhedahht所說:

  1. 由於整數可能不僅僅之含有數字,還有可能以'+'或者'-'開頭,表示整數的正負。因此我們需要把這個字符串的第一個字符做特殊處理。如果第一個字符是'+'號,則不需要做任何操作;如果第一個字符是'-'號,則表明這個整數是個負數,在最後的時候我們要把得到的數值變成負數。
  2. 接着我們試着處理非法輸入。由於輸入的是指針,在使用指針之前,我們要做的第一件是判斷這個指針是不是爲空。如果試着去訪問空指針,將不可避免地導致程序崩潰。
  3. 另外,輸入的字符串中可能含有不是數字的字符。每當碰到這些非法的字符,我們就沒有必要再繼續轉換。
  4. 最後一個需要考慮的問題是溢出問題。由於輸入的數字是以字符串的形式輸入,因此有可能輸入一個很大的數字轉換之後會超過能夠表示的最大的整數而溢出。
    比如,當給的字符串是如左邊圖片所示的時候,有考慮到麼?當然,它們各自對應的正確輸出如右邊圖片所示(假定你是在32位系統下,且編譯環境是VS2008以上):
    3、很快,可能你就會寫下如下代碼:
  1. //copyright@zhedahht 2007    
  2. enum Status {kValid = 0, kInvalid};  
  3. int g_nStatus = kValid;  
  4.   
  5. // Convert a string into an integer  
  6. int StrToInt(const char* str)  
  7. {  
  8.     g_nStatus = kInvalid;  
  9.     long long num = 0;  
  10.   
  11.     if(str != NULL)  
  12.     {  
  13.         const char* digit = str;  
  14.   
  15.         // the first char in the string maybe '+' or '-'  
  16.         bool minus = false;  
  17.         if(*digit == '+')  
  18.             digit ++;  
  19.         else if(*digit == '-')  
  20.         {  
  21.             digit ++;  
  22.             minus = true;  
  23.         }  
  24.   
  25.         // the remaining chars in the string  
  26.         while(*digit != '\0')  
  27.         {  
  28.             if(*digit >= '0' && *digit <= '9')  
  29.             {  
  30.                 num = num * 10 + (*digit - '0');  
  31.   
  32.                 // overflow    
  33.                 if(num > std::numeric_limits<int>::max())  
  34.                 {  
  35.                     num = 0;  
  36.                     break;  
  37.                 }  
  38.   
  39.                 digit ++;  
  40.             }  
  41.             // if the char is not a digit, invalid input  
  42.             else  
  43.             {  
  44.                 num = 0;  
  45.                 break;  
  46.             }  
  47.         }  
  48.   
  49.         if(*digit == '\0')  
  50.         {  
  51.             g_nStatus = kValid;  
  52.             if(minus)  
  53.                 num = 0 - num;  
  54.         }  
  55.     }  
  56.     return static_cast<int>(num);  
  57. }  
    run下上述程序,會發現當輸入字符串是下圖中紅叉叉部分所對應的時候,程序結果出錯:  
    

    兩個問題:

  1. 當輸入的字符串不是數字,而是字符的時候,比如“1a”,上述程序直接返回了0(而正確的結果應該是得到1):
    1. // if the char is not a digit, invalid input  
    2.                   else  
    3.                   {  
    4.                       num = 0;  
    5.                       break;  
    6.                   }  
  2. 處理溢出時,有問題。
    4、把代碼做下微調,如下:
  1. //copyright@SP_daiyq 2013/5/29  
  2. int StrToInt(const char* str)  
  3. {  
  4.     int res = 0; // result  
  5.     int i = 0; // index of str  
  6.     int signal = '+'// signal '+' or '-'  
  7.     int cur; // current digit  
  8.   
  9.     if (!str)  
  10.         return 0;  
  11.   
  12.     // skip backspace  
  13.     while (isspace(str[i]))  
  14.         i++;  
  15.   
  16.     // skip signal  
  17.     if (str[i] == '+' || str[i] == '-')  
  18.     {  
  19.         signal = str[i];  
  20.         i++;  
  21.     }  
  22.   
  23.     // get result  
  24.     while (str[i] >= '0' && str[i] <= '9')  
  25.     {  
  26.         cur = str[i] - '0';  
  27.   
  28.         // judge overlap or not  
  29.         if ( (signal == '+') && (cur > INT_MAX - res*10) )  
  30.         {  
  31.             res = INT_MAX;  
  32.             break;  
  33.         }  
  34.         else if ( (signal == '-') && (cur -1 > INT_MAX - res*10) )  
  35.         {  
  36.             res = INT_MIN;  
  37.             break;  
  38.         }  
  39.   
  40.         res = res * 10 + cur;  
  41.         i++;  
  42.     }  
  43.   
  44.     return (signal == '-') ? -res : res;  
  45. }  
    會發現,上面第4小節所述的第1個問題解決了:
    
    但,即使這樣,上述代碼也還是有問題的。當給定下述測試數據的時候,問題就來了:
需要轉換的字符串                         代碼運行結果         理應得到的正確結果
"    10522545459" 1932610867 2147483647
"         +10523538441s" 1933603849 2147483647
"   +10432359437" 1842424845 2147483647

    什麼問題呢?比如說用上述代碼轉換這個字符串:"    10522545459",它本應得到的正確結果應該是2147483647,但程序實際得到的結果卻是:1932610867。故很明顯,程序沒有很好的解決上面的第2個小問題:溢出問題。

    5、上面說給的程序沒有“很好的解決溢出問題。由於輸入的數字是以字符串的形式輸入,因此有可能輸入一個很大的數字轉換之後會超過能夠表示的最大的整數而溢出。”那麼,到底代碼該如何寫呢?
  1. //copyright@淹死鯊魚ronkins 2013/5/29  
  2. //挑戰題目:http://hero.pongo.cn/Question/Details?ID=47&ExamID=45  
  3. int atoi(const char* str)    
  4. {    
  5.     long long res = 0;    
  6.     int sign = 1;    
  7.   
  8.     while(isspace(*str))++str;    
  9.     if('+' == *str){    
  10.         ++str;    
  11.     }else if('-' == *str){    
  12.         sign = -1;    
  13.         ++str;    
  14.     }    
  15.   
  16.     for(; isdigit(*str); ++str){    
  17.         res *= 10;    
  18.         if(sign > 0)    
  19.             res += (*str - '0');    
  20.         else    
  21.             res -= (*str - '0');    
  22.         if(res >= INT_MAX)return INT_MAX;    
  23.         else if(res <= INT_MIN)return INT_MIN;    
  24.     }    
  25.   
  26.     return res;    
  27. }    
    上面的代碼看似能處理數據溢出的問題,其實它只是做了個取巧,即把返回的值res定義成了long long,如下所示:
  1. long long res = 0;    
    故嚴格說來,我們依然未寫出準確的規範代碼。

    6、那到底該如何解決這個數據溢出的問題呢?庫函數atoi的規定超過int值,按最大值maxint:2147483647來,超過-int按最小值minint:-2147483648來。咱們先來看看Microsoft是如何實現atoi的吧:
  1. //atol函數  
  2. //Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.  
  3. long __cdecl atol(  
  4.     const char *nptr  
  5.     )  
  6. {  
  7.     int c; /* current char */  
  8.     long total; /* current total */  
  9.     int sign; /* if ''-'', then negative, otherwise positive */  
  10.   
  11.     /* skip whitespace */  
  12.     while ( isspace((int)(unsigned char)*nptr) )  
  13.         ++nptr;  
  14.   
  15.     c = (int)(unsigned char)*nptr++;  
  16.     sign = c; /* save sign indication */  
  17.     if (c == ''-'' || c == ''+'')  
  18.         c = (int)(unsigned char)*nptr++; /* skip sign */  
  19.   
  20.     total = 0;  
  21.   
  22.     while (isdigit(c)) {  
  23.         total = 10 * total + (c - ''0''); /* accumulate digit */  
  24.         c = (int)(unsigned char)*nptr++; /* get next char */  
  25.     }  
  26.   
  27.     if (sign == ''-'')  
  28.         return -total;  
  29.     else  
  30.         return total; /* return result, negated if necessary */  
  31. }  
    其中,isspace和isdigit函數的實現代碼爲:
  1. isspace(int x)    
  2. {    
  3.     if(x==' '||x=='/t'||x=='/n'||x=='/f'||x=='/b'||x=='/r')    
  4.         return 1;    
  5.     else     
  6.         return 0;    
  7. }    
  8.   
  9. isdigit(int x)    
  10. {    
  11.     if(x<='9'&&x>='0')             
  12.         return 1;     
  13.     else     
  14.         return 0;    
  15. }   
    然後atoi調用上面的atol函數,如下所示:
  1. //atoi調用上述的atol  
  2. int __cdecl atoi(  
  3.     const char *nptr  
  4.     )  
  5. {  
  6.     //Overflow is not detected. Because of this, we can just use  
  7.     return (int)atol(nptr);  
  8. }  

    但很遺憾的是,上述atoi標準代碼依然返回的是long:

  1. long total; /* current total */  
  2. if (sign == ''-'')  
  3.     return -total;  
  4. else  
  5.     return total; /* return result, negated if necessary */  

    再者,下面這裏定義成long的total與10相乘,即total*10很容易溢出:

  1. long total; /* current total */  
  2. total = 10 * total + (c - ''0''); /* accumulate digit */  
   
     7、繼續尋找。接下來,咱們來看看linux內核中是如何實現此字符串轉換爲整數的問題的。
linux內核中提供了以下幾個函數:
  1. simple_strtol,把一個字符串轉換爲一個有符號長整數;
  2. simple_strtoll,把一個字符串轉換爲一個有符號長長整數;
  3. simple_strtoul,把一個字符串轉換爲一個無符號長整數;
  4. simple_strtoull,把一個字符串轉換爲一個無符號長長整數
    相關源碼及分析如下。
    首先,atoi調下面的strtol:
  1. //linux/lib/vsprintf.c  
  2. //Copyright (C) 1991, 1992  Linus Torvalds  
  3. //simple_strtol - convert a string to a signed long  
  4. long simple_strtol(const char *cp, char **endp, unsigned int base)  
  5. {  
  6.     if (*cp == '-')  
  7.         return -simple_strtoul(cp + 1, endp, base);  
  8.   
  9.     return simple_strtoul(cp, endp, base);  
  10. }  
  11. EXPORT_SYMBOL(simple_strtol);  
    然後,上面的strtol調下面的strtoul:
  1. //simple_strtoul - convert a string to an unsigned long  
  2. unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)  
  3. {  
  4.     return simple_strtoull(cp, endp, base);  
  5. }  
  6. EXPORT_SYMBOL(simple_strtoul);  
    接着,上面的strtoul調下面的strtoull:
  1. //simple_strtoll - convert a string to a signed long long  
  2. long long simple_strtoll(const char *cp, char **endp, unsigned int base)  
  3. {  
  4.     if (*cp == '-')  
  5.         return -simple_strtoull(cp + 1, endp, base);  
  6.   
  7.     return simple_strtoull(cp, endp, base);  
  8. }  
  9. EXPORT_SYMBOL(simple_strtoll);  
    最後,strtoull調_parse_integer_fixup_radix和_parse_integer來處理相關邏輯:
  1. //simple_strtoull - convert a string to an unsigned long long  
  2. unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)  
  3. {  
  4.     unsigned long long result;  
  5.     unsigned int rv;  
  6.   
  7.     cp = _parse_integer_fixup_radix(cp, &base);  
  8.     rv = _parse_integer(cp, base, &result);  
  9.     /* FIXME */  
  10.     cp += (rv & ~KSTRTOX_OVERFLOW);  
  11.   
  12.     if (endp)  
  13.         *endp = (char *)cp;  
  14.   
  15.     return result;  
  16. }  
  17. EXPORT_SYMBOL(simple_strtoull);  
    重頭戲來了。接下來,我們來看上面strtoull函數中的parse_integer_fixup_radix和_parse_integer兩段代碼。如鯊魚所說
  • “真正的處理邏輯主要是在_parse_integer裏面,關於溢出的處理,_parse_integer處理的很優美,
  • 而_parse_integer_fixup_radix是用來自動根據字符串判斷進制的”。
    先來看_parse_integer函數:
  1. //lib/kstrtox.c, line 39    
  2. //Convert non-negative integer string representation in explicitly given radix to an integer.    
  3. //Return number of characters consumed maybe or-ed with overflow bit.    
  4. //If overflow occurs, result integer (incorrect) is still returned.    
  5. unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)    
  6. {    
  7.     unsigned long long res;    
  8.     unsigned int rv;    
  9.     int overflow;    
  10.     
  11.     res = 0;    
  12.     rv = 0;    
  13.     overflow = 0;    
  14.     while (*s) {    
  15.         unsigned int val;    
  16.     
  17.         if ('0' <= *s && *s <= '9')    
  18.             val = *s - '0';    
  19.         else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')    
  20.             val = _tolower(*s) - 'a' + 10;    
  21.         else    
  22.             break;    
  23.     
  24.         if (val >= base)    
  25.             break;    
  26.         /*  
  27.          * Check for overflow only if we are within range of  
  28.          * it in the max base we support (16)  
  29.          */    
  30.         if (unlikely(res & (~0ull << 60))) {    
  31.             if (res > div_u64(ULLONG_MAX - val, base))    
  32.                 overflow = 1;    
  33.         }    
  34.         res = res * base + val;    
  35.         rv++;    
  36.         s++;    
  37.     }    
  38.     *p = res;    
  39.     if (overflow)    
  40.         rv |= KSTRTOX_OVERFLOW;    
  41.     return rv;    
  42. }  
    解釋下兩個小細節:
  1. 上頭出現了個unlikely,其實unlikely和likely經常出現在linux相關內核源碼中
    1. if(likely(value)){  
    2.     //等價於if(likely(value)) == if(value)  
    3. }  
    4. else{  
    5. }  
    likely表示value爲真的可能性更大,而unlikely表示value爲假的可能性更大,這兩個宏被定義成:
    1. //include/linux/compiler.h  
    2. # ifndef likely  
    3. #  define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))  
    4. # endif  
    5. # ifndef unlikely  
    6. #  define unlikely(x)   (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))  
    7. # endif  
  2. 呈現下div_u64的代碼:
    1. //include/linux/math64.h  
    2. //div_u64  
    3. static inline u64 div_u64(u64 dividend, u32 divisor)  
    4. {  
    5.     u32 remainder;  
    6.     return div_u64_rem(dividend, divisor, &remainder);  
    7. }  
    8.   
    9. //div_u64_rem  
    10. static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)  
    11. {  
    12.     *remainder = dividend % divisor;  
    13.     return dividend / divisor;  
    14. }  
    最後看下_parse_integer_fixup_radix函數:
  1. //lib/kstrtox.c, line 23  
  2. const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)  
  3. {  
  4.     if (*base == 0) {  
  5.         if (s[0] == '0') {  
  6.             if (_tolower(s[1]) == 'x' && isxdigit(s[2]))  
  7.                 *base = 16;  
  8.             else  
  9.                 *base = 8;  
  10.         } else  
  11.             *base = 10;  
  12.     }  
  13.     if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')  
  14.         s += 2;  
  15.     return s;  
  16. }  
    OK,至此,字符串轉換成整數的問題算是已經解決。如果面試官繼續問你,如何把整數轉換成字符串呢?請讀者思考,同時也歡迎於本文評論下或hero上show your code


第三十一章、字符串匹配問題

字符串匹配問題,給定一串字符串,按照指定規則對其進行匹配,並將匹配的結果保存至output數組中,多個匹配項用空格間隔,最後一個不需要空格。

要求:

  1. 匹配規則中包含通配符?和*,其中?表示匹配任意一個字符,*表示匹配任意多個(>=0)字符。
  2. 匹配規則要求匹配最大的字符子串,例如a*d,匹配abbdd而非abbd,即最大匹配子串。
  3. 匹配後的輸入串不再進行匹配,從當前匹配後的字符串重新匹配其他字符串。

請實現函數:char* my_find(char  input[],   char rule[])

舉例說明

input:abcadefg
rule:a?c
output:abc

input :newsadfanewfdadsf
rule: new
output: new new

input :breakfastfood
rule: f*d
output:fastfood

注意事項:

  1. 自行實現函數my_find,勿在my_find函數裏夾雜輸出,且不準用C、C++庫,和Java的String對象;
  2. 請注意代碼的時間,空間複雜度,及可讀性,簡潔性;
  3. input=aaa,rule=aa時,返回一個結果aa,即可。

    1、本題與上述第三十章的題不同,上題字符串轉換成整數更多考察對思維的全面性和對細節的處理,本題則更多的是編程技巧。閒不多說,直接上代碼:

  1. //copyright@cao_peng 2013/4/23  
  2. int str_len(char *a) {  //字符串長度  
  3.     if (a == 0) {  
  4.         return 0;  
  5.     }  
  6.     char *t = a;  
  7.     for (;*t;++t)  
  8.         ;  
  9.     return (int) (t - a);  
  10. }  
  11.   
  12. void str_copy(char *a,const char *b,int len) {  //拷貝字符串 a = b  
  13.     for (;len > 0; --len, ++b,++a) {  
  14.         *a = *b;  
  15.     }  
  16.     *a = 0;  
  17. }  
  18.   
  19. char *str_join(char *a,const char *b,int lenb) { //連接字符串 第一個字符串被回收  
  20.     char *t;  
  21.     if (a == 0) {  
  22.         t = (char *) malloc(sizeof(char) * (lenb + 1));   
  23.         str_copy(t, b, lenb);  
  24.         return t;  
  25.     }  
  26.     else {  
  27.         int lena = str_len(a);  
  28.         t = (char *) malloc(sizeof(char) * (lena + lenb + 2));  
  29.         str_copy(t, a, lena);  
  30.         *(t + lena) = ' ';  
  31.         str_copy(t + lena + 1, b, lenb);  
  32.         free(a);  
  33.         return t;  
  34.     }  
  35. }  
  36.   
  37. int canMatch(char *input, char *rule) { // 返回最長匹配長度 -1表示不匹配   
  38.     if (*rule == 0) { //已經到rule尾端  
  39.         return 0;  
  40.     }  
  41.     int r = -1 ,may;  
  42.     if (*rule == '*') {  
  43.         r = canMatch(input, rule + 1);  // *匹配0個字符  
  44.         if (*input) {  
  45.             may = canMatch(input + 1, rule);  // *匹配非0個字符  
  46.             if ((may >= 0) && (++may > r)) {  
  47.                 r = may;  
  48.             }  
  49.         }  
  50.     }  
  51.     if (*input == 0) {  //到尾端  
  52.         return r;  
  53.     }  
  54.     if ((*rule == '?') || (*rule == *input)) {  
  55.         may = canMatch(input + 1, rule + 1);  
  56.         if ((may >= 0) && (++may > r)) {  
  57.             r = may;  
  58.         }  
  59.     }  
  60.     return r;  
  61. }  
  62.   
  63. char * my_find(char  input[],   char rule[]) {  
  64.     int len = str_len(input);  
  65.     int *match = (int *) malloc(sizeof(int) * len);  //input第i位最多能匹配多少位 匹配不上是-1  
  66.     int i,max_pos = - 1;  
  67.     char *output = 0;  
  68.   
  69.     for (i = 0; i < len; ++i) {  
  70.         match[i] = canMatch(input + i, rule);  
  71.         if ((max_pos < 0) || (match[i] > match[max_pos])) {  
  72.             max_pos = i;  
  73.         }  
  74.     }  
  75.     if ((max_pos < 0) || (match[max_pos] <= 0)) {  //不匹配  
  76.         output = (char *) malloc(sizeof(char));  
  77.         *output = 0;   // \0  
  78.         return output;  
  79.     }  
  80.     for (i = 0; i < len;) {  
  81.         if (match[i] == match[max_pos]) { //找到匹配  
  82.             output = str_join(output, input + i, match[i]);  
  83.             i += match[i];  
  84.         }  
  85.         else {  
  86.             ++i;  
  87.         }  
  88.     }  
  89.     free(match);  
  90.     return output;  
  91. }  
     2、本題也可以直接寫出DP方程,如下代碼所示:
  1. //copyright@chpeih 2013/4/23  
  2. char * my_find(char  input[],   char rule[]) {  
  3.     int len = str_len(input);  
  4.     int *match = (int *) malloc(sizeof(int) * len);  //input第i位最多能匹配多少位 匹配不上是-1  
  5.     int i,max_pos = - 1;  
  6.     char *output = 0;  
  7.   
  8.     for (i = 0; i < len; ++i) {  
  9.         match[i] = canMatch(input + i, rule);  
  10.         if ((max_pos < 0) || (match[i] > match[max_pos])) {  
  11.             max_pos = i;  
  12.         }  
  13.     }  
  14.     if ((max_pos < 0) || (match[max_pos] <= 0)) {  //不匹配  
  15.         output = (char *) malloc(sizeof(char));  
  16.         *output = 0;   // \0  
  17.         return output;  
  18.     }  
  19.     for (i = 0; i < len;) {  
  20.         if (match[i] == match[max_pos]) { //找到匹配  
  21.             output = str_join(output, input + i, match[i]);  
  22.             i += match[i];  
  23.         }  
  24.         else {  
  25.             ++i;  
  26.         }  
  27.     }  
  28.     free(match);  
  29.     return output;  
  30. }  
  31.   
  32.   
  33. char* my_find(char  input[],   char rule[])  
  34. {  
  35.     //write your code here  
  36.     int len1,len2;  
  37.     for(len1 = 0;input[len1];len1++);  
  38.     for(len2 = 0;rule[len2];len2++);  
  39.     int MAXN = len1>len2?(len1+1):(len2+1);  
  40.     int  **dp;  
  41.   
  42.     //dp[i][j]表示字符串1和字符串2分別以i j結尾匹配的最大長度  
  43.     //記錄dp[i][j]是由之前那個節點推算過來  i*MAXN+j  
  44.     dp = new int *[len1+1];  
  45.     for (int i = 0;i<=len1;i++)  
  46.     {  
  47.         dp[i] = new int[len2+1];  
  48.     }  
  49.     dp[0][0] = 0;  
  50.   
  51.     for(int i = 1;i<=len2;i++)dp[0][i] = -1;  
  52.     for(int i = 1;i<=len1;i++)dp[i][0] = 0;  
  53.     for (int i = 1;i<=len1;i++)  
  54.     {  
  55.         for (int j = 1;j<=len2;j++)  
  56.         {  
  57.             if(rule[j-1]=='*'){  
  58.                 dp[i][j] = -1;  
  59.                 if (dp[i-1][j-1]!=-1)  
  60.                 {  
  61.                     dp[i][j] = dp[i-1][j-1]+1;  
  62.   
  63.                 }  
  64.                 if (dp[i-1][j]!=-1 && dp[i][j]<dp[i-1][j]+1)  
  65.                 {  
  66.                     dp[i][j] = dp[i-1][j]+1;  
  67.   
  68.                 }  
  69.             }else if (rule[j-1]=='?')  
  70.             {  
  71.                 if(dp[i-1][j-1]!=-1){  
  72.                     dp[i][j] = dp[i-1][j-1]+1;  
  73.   
  74.                 }else dp[i][j] = -1;  
  75.             }   
  76.             else  
  77.             {  
  78.                 if(dp[i-1][j-1]!=-1 && input[i-1]==rule[j-1]){  
  79.                     dp[i][j] = dp[i-1][j-1]+1;  
  80.                 }else dp[i][j] = -1;  
  81.             }  
  82.         }  
  83.     }  
  84.   
  85.     int m = -1;//記錄最大字符串長度  
  86.     int *ans = new int[len1];  
  87.     int count_ans = 0;//記錄答案個數  
  88.     char *returnans = new char[len1+1];  
  89.     int count = 0;  
  90.   
  91.     for(int i = 1;i<=len1;i++)  
  92.         if (dp[i][len2]>m){  
  93.             m = dp[i][len2];  
  94.             count_ans = 0;  
  95.             ans[count_ans++] = i-m;  
  96.         }else if(dp[i][len2]!=-1 &&dp[i][len2]==m){  
  97.             ans[count_ans++] = i-m;  
  98.         }  
  99.         if (count_ans!=0)  
  100.         {      
  101.             int len = ans[0];  
  102.             for (int i = 0;i<m;i++)  
  103.             {  
  104.                 printf("%c",input[i+ans[0]]);  
  105.                 returnans[count++] = input[i+ans[0]];  
  106.             }  
  107.             for (int j = 1;j<count_ans;j++)  
  108.             {  
  109.                 printf(" ");  
  110.                 returnans[count++] = ' ';  
  111.                 len = ans[j];  
  112.                 for (int i = 0;i<m;i++)  
  113.                 {  
  114.                     printf("%c",input[i+ans[j]]);  
  115.                     returnans[count++] = input[i+ans[j]];  
  116.                 }  
  117.             }  
  118.             printf("\n");  
  119.             returnans[count++] = '\0';  
  120.         }  
  121.   
  122.         return returnans;  
  123. }  
     歡迎於本文評論下或hero上show your code


參考文獻及推薦閱讀

  1. http://zhedahht.blog.163.com/blog/static/25411174200731139971/
  2. http://hero.pongo.cn/,本文大部分代碼都取自左邊hero上參與答題者提交的代碼,歡迎你也去挑戰;
  3. 字符串轉換成整數題目完整描述:http://hero.pongo.cn/Question/Details?ID=47&ExamID=45
  4. 字符串匹配問題題目完整描述:http://hero.pongo.cn/Question/Details?ID=28&ExamID=28
  5. linux3.8.4版本下的相關字符串整數轉換函數概覽:https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/lib/vsprintf.c?id=refs/tags/v3.9.4
  6. 關於linux中的likely和unlikely:http://blog.21ic.com/user1/5593/archives/2010/68193.html

發佈了59 篇原創文章 · 獲贊 9 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章