算法竞赛入门经典 例题9-7

UVa 11584

Partitioning by Palindromes

将一个字符串进行划分,使得划分后的每一部分都是回文字符串,求给定字符串的最小划分。

假设已经找到了前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,所以长度为12的回文串需要单独计算。

#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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值