標籤:style blog http color io for art ar
73.對稱字串的最大長度(字串)。
題目:輸入一個字串,輸出該字串中對稱的子字串的最大長度。
比如輸入字串“google”,由於該字串裡最長的對稱子字串是“goog”,因此輸出 4。
雖然知道會有簡單的方法,可腦子就是轉不動了,只好用最常見的,對所有可能的字串判斷是否為對稱的。再輸出最大長度 O(N3)
/*73.對稱字串的最大長度(字串)。題目:輸入一個字串,輸出該字串中對稱的子字串的最大長度。比如輸入字串“google”,由於該字串裡最長的對稱子字串是“goog”,因此輸出 4。*/#include <stdio.h>#include <string.h>bool issymmetry(char * in, int len) //判斷字串是否對稱{ int i, j; for(i = 0, j = len - 1; i < j ; i++, j--) { if(in[i] != in[j]) { return false; } } return true;}int maxSubSymLen(char * in, int len){ int nlen; for(nlen = len; nlen >= 1; nlen--) //按長度迴圈 { if(nlen == 1) { return 1; } else { int i; for(i = 0; i <= len - nlen; i++) //首字母位置迴圈 { if(issymmetry(in + i, nlen)) { for(int j = i; j < i + nlen; j++) { printf("%c ", in[j]); } return nlen; } } } }}int main(){ char a[40] = "asdgjoalsgjeslhfelgjdjglejf"; int ans = maxSubSymLen(a, strlen(a)); return 0;}
網上O(N2)解法是 長度從小向大迴圈
http://blog.163.com/[email protected]/blog/static/1113522592011912103756405/
如果我們換一種思路,我們從裡向外來判斷。也就是我們先判斷子字串A是不是對稱的。如果A不是對稱的,那麼向該子字串兩端各延長一個字元得到的字串肯定不是對稱的。如果A對稱,那麼我們只需要判斷A兩端延長的一個字元是不是相等的,如果相等,則延長後的字串是對稱的。因此在知道A是否對稱之後,只需要O(1)的時間就能知道aAa是不是對稱的。
/*取得所有對稱子串的最大長度時間複雜度: O(n^2)*/int GetLongestSymmetricalLength(char* pString){ if(pString == NULL) return 0; int symmeticalLength = 1; char* pChar = pString; while(*pChar != ‘\0‘) { // Substrings with odd length char* left = pChar - 1; char* right = pChar + 1; while(left >= pString && *right != ‘\0‘ && *left == *right) { left--; right++; } int newLength = right - left - 1; //退出while迴圈時,*left != *right if(newLength > symmeticalLength) symmeticalLength = newLength; // Substrings with even length left = pChar; right = pChar + 1; while(left >= pString && *right != ‘\0‘ && *left == *right) { left--; right++; } newLength = right - left - 1; //退出while迴圈時,*left != *right if(newLength > symmeticalLength) symmeticalLength = newLength; pChar++; } return symmeticalLength;}
居然還有O(N)的演算法!!
http://blog.csdn.net/hackbuteer1/article/details/6686263
經常有一些題目圍繞迴文子串進行討論,比如 HDOJ_3068_最長迴文,求最長迴文子串的長度。樸素演算法是依次以每一個字元為中心向兩側進行擴充,顯然這個複雜度是O(N^2)的,關於字串的題目常用的演算法有KMP、尾碼數組、AC自動機,這道題目利用擴充KMP可以解答,其時間複雜度也很快O(N*logN)。但是,今天筆者介紹一個專門針對迴文子串的演算法,其時間複雜度為O(n),這就是manacher演算法。
大家都知道,求迴文串時需要判斷其奇偶性,也就是求aba和abba的演算法略有差距。然而,這個演算法做了一個簡單的處理,很巧妙地把奇數長度迴文串與偶數長度迴文串統一考慮,也就是在每個相鄰的字元之間插入一個分隔字元,串的首尾也要加,當然這個分隔字元不能再原串中出現,一般可以用‘#’或者‘$’等字元。例如:
原串:abaab
新串:#a#b#a#a#b#
這樣一來,原來的奇數長度迴文串還是奇數長度,偶數長度的也變成以‘#’為中心的奇數迴文串了。
接下來就是演算法的中心思想,用一個輔助數組P記錄以每個字元為中心的最長迴文半徑,也就是P[i]記錄以Str[i]字元為中心的最長迴文串半徑。P[i]最小為1,此時迴文串為Str[i]本身。
我們可以對上述例子寫出其P數組,如下
新串: # a # b # a # a # b #
P[] : 1 2 1 4 1 2 5 2 1 2 1
我們可以證明P[i]-1就是以Str[i]為中心的迴文串在原串當中的長度。
證明:
1、顯然L=2*P[i]-1即為新串中以Str[i]為中心最長迴文串長度。
2、以Str[i]為中心的迴文串一定是以#開頭和結尾的,例如“#b#b#”或“#b#a#b#”所以L減去最前或者最後的‘#’字元就是原串中長度的二倍,即原串長度為(L-1)/2,化簡的P[i]-1。得證。
依次從前往後求得P數組就可以了,這裡用到了DP(動態規劃)的思想,也就是求P[i]的時候,前面的P[]值已經得到了,我們利用迴文串的特殊性質可以進行一個大大的最佳化。
#include <stdio.h>#define M 110010char b[M],a[M<<1];int p[M<<1];int Min(int a,int b){ return a<b?a:b;}int main(void){ int i,n,id,MaxL,MaxId; while(scanf("%s",&b[1])!=EOF) { MaxL=MaxId=0; for(i=1;b[i]!=‘\0‘;i++) { a[(i<<1)]=b[i]; a[(i<<1)+1]=‘#‘; } a[0]=‘?‘;a[1]=‘#‘; n=(i<<1)+2;a[n]=0; MaxId=MaxL=0; for(i=1;i<n;i++) { if(MaxId>i) { p[i]=Min(p[2*id-i],MaxId-i); } else { p[i]=1; } while(a[i+p[i]]==a[i-p[i]]) { p[i]++; } if(p[i]+i>MaxId) { MaxId=p[i]+i; id=i; } if(p[i]>MaxL) { MaxL=p[i]; } } printf("%d\n",MaxL-1); } return 0;}