我想检查字符串是否以回文子串开头;我正在寻找从我的数组开始的最长的回文子串。
这是O(n*n)
中的一个简单方法。有更聪明的方法吗?
//not safe for empty string
bool isPalindrome(string s)
{
string rev = s;
std::reverse(rev.begin(), rev.end());
return rev == s;
}
int startWithPalindome(const string a)
{
int N = a.length();
for (int len = N; len > 0; len--)
{
bool isPal = isPalindrome(a.substr(0,len));
if (isPal)
return len;
}
return -1;
}
编辑:澄清:我知道这个代码可以通过多种方式进行改进,进行各种调整,但是我有兴趣减少渐近时间的复杂性。
答案 0 :(得分:0)
优化startWithPalindrome()
您的方法是寻找最大可能的回文,并使用蛮力连续减少您考虑的子串的大小,直到找到回文。
您可以轻松修剪大量的比较,不是从字符串的总大小开始,而是使用rfind()
查找第一个字符的最后一次出现。那么你可以向后迭代到该字符的前一个位置,依此类推:
int startWithPalindome(const string a)
{
if (a.length()>1)
{
for (int N = a.rfind(a[0]); N!=string::npos && N>0; N= a.rfind(a[0],N-1) ) {
if ( isPalindrome(a.substr(0,N+1)) )
return N+1;
}
}
return -1;
}
顺便说一句:优化isPalindrome()
您的isPalindrom()
版本将空字符串或单个字符串视为回文结构。你可以保持这样,但我建议消除这种情况。
我建议你使用一个小变体,它不会复制字符串,而只是从开头到结尾遍历它,因此(几乎)执行最少数量的操作:
bool isPalindrome(string s)
{
if (s.length()<2) // empty strings and singles chars are no palindromes !
return false;
for (auto f=s.cbegin(), r=s.cend()-1; f!=r; r--) {
if (*f!=*r) // if the nth letter from start doesn't match nth from ens
return false; // not a palindrom
if (++f==r) // if middle of string is between two chars
break;
}
return true; // we meet in the middle so it's a palindrome
}