题目:给定一字符串,求最长的回文子串。
解法一、暴力法
循环查找字符串中的所有回文子串,时间复杂度O(N3):
第一遍循环,选取开始点 i
第二遍循环,选取结束位置 j
第三遍循环,判断 i-j 是否为回文字符串
int palindromeA(const string &str, string &result)
{
result.clear();
if (str.size() < 2) {
result = str;
return str.size();
}
int maxNum = 1;
result = str.substr(0, 1);
for (int i = 0; i < str.size(); ++i) {
for (int j = str.size() - 1; j > i; --j) {
int m = i;
int n = j;
// 当两个字符不相等时(不是回文),或者m >= n时跳出循环(是i-j中最大回文)
while(str[m] == str[n]) {
if (m >= n) {
break;
} else {
m += 1;
n -= 1;
}
}
if (m >= n && n >= 0 && maxNum < j - i + 1) {
maxNum = j - i + 1;
result = str.substr(i, maxNum);
break;
}
}
if (maxNum == str.size()) {
break;
}
}
return maxNum;
}
解法二、中心扩展法:
从中心向外扩展。分为两种情况:第一种当回文串长度为奇数的情况;第二种当回文串长度为偶数的情况。左右同时向外扩展,当左右不相同时停止扩展,记录最长回文串长度及起始位置。时间复杂度O(N2):
int palindromeB(const string &str, string &result)
{
result.clear();
if (str.size() < 2) {
result = str;
return str.size();
}
int maxNum = 1;
int maxStart = 0;
result = str.substr(0, 1);
for (int i = 0; i < str.size(); ++i) {
// 为0时偶数,为1时奇数
for (int j = 0; j < 2; ++j) {
int m = i - j;
int n = i + 1;
while (m >= 0 && n < str.size() && str[m] == str[n]) {
m -= 1;
n += 1;
}
// 最后判断为回文子串后 m自减1,n自加1,所以长度为 n-m-1.
if (maxNum < n - m - 1) {
maxNum = n - m - 1;
maxStart = m + 1;
result = str.substr(maxStart, maxNum);
}
}
}
return maxNum;
}
解法三、动态规划法:
首先初始化一个二维的dst数组(str.size() * str.size())。dst[i][j]:表示区间范围[i,j] 的子串是否是回文子串,如果是dst[i][j]为1,否则为0。
判断结果是两种,就是str[i]与str[j]相等,str[i]与str[j]不相等这两种。
当str[i]与str[j]不相等,dst[i][j]是0。
当str[i]与str[j]相等时,这就复杂一些了,有如下三种情况
情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
情况二:下标i 与 j相差为1,例如aa,也是回文子串
情况三:下标i 与 j相差大于1的时候,例如cabac,此时str[i]与str[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dst[i + 1][j - 1]是否为1。
从推导步骤可以看出,再求解dst[i][j]时,必须先求得dst[i + 1][j - 1],因此需要使用自底向上的设计方法进行遍历,即动态规划中的迭代法,时间复杂度O(N2):
int palindromeC(const string &str, string &result)
{
result.clear();
if (str.size() < 2) {
result = str;
return str.size();
}
char dst[str.size()][str.size()] = {0};
for (int i = str.size() - 1; i >= 0; --i) {
for (int j = i; j < str.size(); ++j) {
if (str[i] == str[j]) {
if (i == j || j - i == 1 || dst[i + 1][j - 1] == 1) {
dst[i][j] = 1;
}
}
}
}
int maxStart = 0;
int maxNum = 1;
result = str.substr(0, 1);
for (int i = 0; i < str.size(); ++i) {
for (int j = 0; j < str.size(); ++j) {
if (dst[i][j] == 1) {
int num = (j > i) ? (j - i) : (i - j);
num = num + 1;
if (maxNum < num) {
maxNum = num;
maxStart = j > i ? i : j;
result = str.substr(maxStart, maxNum);
}
}
}
}
return maxNum;
}
解法三、Manachar算法(马拉车算法):
Manachar算法主要是处理字符串中关于回文串的问题的,它可以在 O(N) 的时间处理出以字符串中每一个字符为中心的回文串半径,由于将原字符串处理成两倍长度的新串,在每两个字符之间加入一个特定的特殊字符,因此原本长度为偶数的回文串就成了以中间特殊字符为中心的奇数长度的回文串了。
Manachar算法算是一种中心扩展法的变种和优化,在字符串ababa中,分别以a、b、a、b、a为中心,向两边扩散,可以找到所有的回文字符串。但是这种方案有个缺陷,当字符串长度为偶数时会失效。
百度百科资料:
int palindromeD(const string &str, string &result)
{
result.clear();
if (str.size() < 2) {
result = str;
return str.size();
}
vector<char> s; // 重构字符串,加入'#'
s.push_back('#');
for (char c : str) {
s.push_back(c);
s.push_back('#');
}
int maxNum = 1;
result = str.substr(0, 1);
for (int i = 0; i < s.size(); ++i) {
int m = i - 1;
int n = i + 1;
while(m >= 0 && n < s.size() && s[m] == s[n]) {
m--;
n++;
}
int num = n - i; // 字符中心的最长回文字串的最右字符到该字符的长度
if (maxNum < num - 1) {
maxNum = num - 1;
result.clear();
for (int k = m + 1; k < n; ++k) {
if (s[k] != '#') {
result += s[k];
}
}
}
}
return maxNum;
}
测试以及结果:
int main()
{
string s;
const string str1 = "a";
const string str2 = "aa";
const string str3 = "ab";
const string str4 = "aba";
const string str5 = "abcddddcba";
const string str6 = "asabcdefgigfedcbadw";
cout << "str1-A:" << palindromeA(str1, s) << ":" << s << endl;
cout << "str2-A:" << palindromeA(str2, s) << ":" << s << endl;
cout << "str3-A:" << palindromeA(str3, s) << ":" << s << endl;
cout << "str4-A:" << palindromeA(str4, s) << ":" << s << endl;
cout << "str5-A:" << palindromeA(str5, s) << ":" << s << endl;
cout << "str6-A:" << palindromeA(str6, s) << ":" << s << endl;
cout << endl;
cout << "str1-B:" << palindromeB(str1, s) << ":" << s << endl;
cout << "str2-B:" << palindromeB(str2, s) << ":" << s << endl;
cout << "str3-B:" << palindromeB(str3, s) << ":" << s << endl;
cout << "str4-B:" << palindromeB(str4, s) << ":" << s << endl;
cout << "str5-B:" << palindromeB(str5, s) << ":" << s << endl;
cout << "str6-B:" << palindromeB(str6, s) << ":" << s << endl;
cout << endl;
cout << "str1-C:" << palindromeC(str1, s) << ":" << s << endl;
cout << "str2-C:" << palindromeC(str2, s) << ":" << s << endl;
cout << "str3-C:" << palindromeC(str3, s) << ":" << s << endl;
cout << "str4-C:" << palindromeC(str4, s) << ":" << s << endl;
cout << "str5-C:" << palindromeC(str5, s) << ":" << s << endl;
cout << "str6-C:" << palindromeC(str6, s) << ":" << s << endl;
cout << endl;
cout << "str1-D:" << palindromeD(str1, s) << ":" << s << endl;
cout << "str2-D:" << palindromeD(str2, s) << ":" << s << endl;
cout << "str3-D:" << palindromeD(str3, s) << ":" << s << endl;
cout << "str4-D:" << palindromeD(str4, s) << ":" << s << endl;
cout << "str5-D:" << palindromeD(str5, s) << ":" << s << endl;
cout << "str6-D:" << palindromeD(str6, s) << ":" << s << endl;
return 0;
}
文章来源:https://www.toymoban.com/news/detail-693597.html
文章来源地址https://www.toymoban.com/news/detail-693597.html
到了这里,关于C++多种解法求最大回文子串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!