題目:輸入一個字符串,輸出該字符串中對稱的子字符串的最大長度。比如輸入字符串“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;
}
