题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
http://zhedahht.blog.163.com/blog/static/25411174201063105120425/
引子:判断字符串是否对称
要判断一个字符串是不是对称的,不是一件很难的事情。我们可以先得到字符串首尾两个字符,判断是不是相等。如果不相等,那该字符串肯定不是对称的。否则我们接着判断里面的两个字符是不是相等,以此类推。
解法一:O(n3)的算法
现在我们试着来得到对称子字符串的最大长度。最直观的做法就是得到输入字符串的所有子字符串,并逐个判断是不是对称的。如果一个子字符串是对称的,我们就得到它的长度。这样经过比较,就能得到最长的对称子字符串的长度了。
#include<iostream> #include<stdio.h> #include<string> using namespace std; char str1[10003]; //char str2[1002]; int main() { bool IsSymmetrical(char *pBegin,char *pEnd); int GetLongestSymmetricalLength_1(char *pString); while(gets(str1)) { cout<<"最大对称子串的长度为:"<<GetLongestSymmetricalLength_1(str1)<<endl; } return 0; } // Whether a string between pBegin and pEnd is symmetrical bool IsSymmetrical(char *pBegin,char *pEnd) { if(pBegin==NULL||pEnd==NULL||pBegin>pEnd) return false; while(pBegin<pEnd) { if(*pBegin!=*pEnd) return false; pBegin++; pEnd--; } return true; } // Get the longest length of its all symmetrical substrings // Time needed is O(T^3) int GetLongestSymmetricalLength_1(char *pString) { if(pString==NULL) return 0; int symmetricalLength=1; char *pFirst=pString; int length=strlen(pString); while(pFirst<&pString[length-1]) { char *pLast=pFirst+1; while(pLast<=&pString[length-1]) { if(IsSymmetrical(pFirst,pLast)) { int newLength=pLast-pFirst+1; if(newLength>symmetricalLength) symmetricalLength=newLength; } pLast++; } pFirst++; } return symmetricalLength; }
时间效率:由于我们需要两重while循环,每重循环需要O(n)的时间。另外,我们在循环中调用了IsSymmetrical,每次调用也需要O(n)的时间。因此整个函数的时间效率是O(n3)。
仔细分析上述方法的比较过程,我们就能发现其中有很多重复的比较。假设我们需要判断一个子字符串具有aAa的形式(A是aAa的子字符串,可能含有多个字符)。我们先把pFirst指向最前面的字符a,把pLast指向最后面的字符a,由于两个字符相同,我们在IsSymtical函数内部向后移动pFirst,向前移动pLast,以判断A是不是对称的。接下来若干步骤之后,由于A也是输入字符串的一个子字符串,我们需要再一次判断它是不是对称的。也就是说,我们重复多次地在判断A是不是对称的。
造成上述重复比较的根源在于IsSymmetrical的比较是从外向里进行的。在判断aAa是不是对称的时候,我们不知道A是不是对称的,因此需要花费O(n)的时间来判断。下次我们判断A是不是对称的时候,我们仍然需要O(n)的时间。
解法二:O(n2)的算法
换一种思路,我们从里向外来判断。也就是我们先判断子字符串A是不是对称的。如果A不是对称的,那么向该子字符串两端各延长一个字符得到的字符串肯定不是对称的。如果A对称,那么我们只需要判断A两端延长的一个字符是不是相等的,如果相等,则延长后的字符串是对称的。因此在知道A是否对称之后,只需要O(1)的时间就能知道aAa是不是对称的。
#include<iostream> #include<stdio.h> #include<string> using namespace std; char str1[10003]; int main() { int GetLongestSymmetricalLength_2(char *pString); while(gets(str1)) { cout<<"最大对称子串的长度为:"<<GetLongestSymmetricalLength_2(str1)<<endl; } return 0; } // Get the longest length of its all symmetrical substrings // Time needed is O(T^2) int GetLongestSymmetricalLength_2(char *pString) { if(pString==NULL) return 0; int symmetricalLength=1; char *pChar=pString; while(*pChar!='\0') { // Substrings with even length char *pFirst=pChar; char *pLast=pChar+1; while( (pFirst>=pString) && (*pLast!='\0') && (*pFirst==*pLast) ) { pLast++; pFirst--; } int newLength=pLast-pFirst-1; if(newLength>symmetricalLength) symmetricalLength=newLength; // Substrings with odd length pFirst=pChar-1; pLast=pChar+1; while( (pFirst>=pString) && (*pLast!='\0') && (*pFirst==*pLast) ) { pFirst--; pLast++; } newLength=pLast-pFirst-1; if(newLength>symmetricalLength) symmetricalLength=newLength; pChar++; } return symmetricalLength; }