UVa 11584
将一个字符串进行划分,使得划分后的每一部分都是回文字符串,求给定字符串的最小划分。
假设已经找到了前end个字符的最小划分,现在加入第end + 1个字符,可以将第end + 1个字符作为结尾,向前寻找所有可能的回文串,设回文串的起点为begin,那么可以将str[begin] ~ str[end + 1]作为一个新的划分,和前begin - 1个字符的最优情况进行组合,得到前end个字符的划分方法,最后在其中取最小值即可。递推公式为Group[end] = min(Group[begin - 1] + 1, Palindrome[begin][end] == true)。
如果每次都重新判断回文串,那么在O(n ^ 2)的复杂度上会再引入O(n)的复杂度,使得整体复杂度提升到O(n ^ 3)。为了降低复杂度,可以提前将所有的回文串都计算出来,然后直接判断即可。在字符串中查找所有的回文串的时间复杂度也为O(n ^ 3),但是也存在动态规划的方法。
假设已经找到了前end个字符的所有回文串,现在加入第end + 1个字符,如果第end + 1个字符是一个回文串的结尾(长度大于1),那么第end个字符也是一个回文串的结尾,其对应的开头为第begin个字符,如果str[begin - 1] == str[end],则str[begin - 1][end]就是一个回文串。这种方式找到的回文串最小长度为3,所以长度为1和2的回文串需要单独计算。
#include <iostream>
#include <string>
#include <vector>
#include <climits>
using namespace std;
void findPalindrome(const string &str, vector<vector<bool>> &Palindrome)
{
Palindrome[0][0] = true;
for (size_t end = 1; end < str.size(); end++)
{
Palindrome[end][end] = true;
Palindrome[end - 1][end] = Palindrome[end][end - 1] = str[end - 1] == str[end];
for (size_t begin = 1; begin < end; begin++)
{
if (Palindrome[begin][end - 1] && str[begin - 1] == str[end]) {
Palindrome[begin - 1][end] = true;
Palindrome[end][begin - 1] = true;
}
}
}
}
void findMinGroup(const string &str, const vector<vector<bool>> &Palindrome)
{
vector<int> Group(str.size(), INT_MAX);
Group[0] = 1;
for (size_t end = 1; end < str.size(); end++)
{
if (Palindrome[0][end]) Group[end] = 1;
for (size_t begin = 1; begin <= end; begin++)
{
if (Palindrome[begin][end]) {
if (Group[end] > Group[begin - 1] + 1) {
Group[end] = Group[begin - 1] + 1;
}
}
}
}
cout << Group.back() << endl;
}
int main()
{
int n = 0;
string str;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> str;
vector<vector<bool>> Palindrome(str.size(), vector<bool>(str.size(), false));
findPalindrome(str, Palindrome);
findMinGroup(str, Palindrome);
}
return 0;
}
/*
3
racecar
fastcar
aaadbccb
*/
本文深入探讨了UVa11584问题——分割回文子串的算法解决方案。通过动态规划预处理所有可能的回文串,实现字符串的最小分割,确保每部分都是回文串。文章提供了详细的算法流程和C++代码实现,包括如何高效地查找回文串并确定最小分割数。
3038

被折叠的 条评论
为什么被折叠?



