Palindrome Partitioning II

29 篇文章 0 订阅

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.


题意: 给定一字符串,求最少切的次数,是的切割所得的所有字串都为回文串!

最开始想的是递归 + dp,dp[i j] 表示从s[i j] 需要的最少的切割的次数,

dp[i j] = min{dp[i k] + dp[k + 1 j]  + 1 | k = [i ,j), i j = [0 s.size()]};

    此解法,i j扫描时为O(n ^2) ,同时对k的扫描为O(n),总体的复杂度为O(n ^3),

当数据长度为1400+是超时。于是想着压缩dp,dp[i] 表示s[0 i]需要的最少切割次数,

dp[i] = min{dp[k] + 1 | k = [0 i - 1] && s[k i]为回文串};

当程序进行到i时, s[0 i-1]已经考虑了所有的最优切法,加入s[i]时,需要考虑的增加的可能的切法

即为{s[0 k] ,s[k + 1, i] | s[k + 1 i]为回文串};

因为当加入i时,切法要么是在原来的基础上+1 ,要么是减少原来的切割次数,

而能减少切割次数的情况只能是s[k]与 s[i]之前的字串组成会回文串,这里+1的情况实际上是k = i的特殊情况

      最开始当计算dp[i]时,我的解法是从0 --i 扫描k计算k[i]是否是回文串,然而还是会超时,

此解法时间复杂度为O(n^2),其实在判断s[k i]是否是回文串时也是O(n),复杂度也接近O(n^3),超时!

      因此,对求回文串的解法还要优化,用symt[i](symt为 vector<vector<int>>)表示 i与之前所有下标k,使得s[k i]为回文串,

symt[i] = {i,L,s[i- 1][k] - 1 | L= (i - 1 && s[L - 1]==s[i]), k 满足s[s[i - 1][k] - 1 ] ==  s[i]},

因为当s[i j]为回文串时,s[i+ 1, j - 1]一定为回文串,因为k 属于{0 ...i- 1},所有还需考虑

s[i-1,i]和s[i,i]!次解法最坏为O(n^3),但实际情况中并不是有这么多回文子串!


超时代码:

const int MAX = 5000+ 5;
int dp[MAX][MAX];
int c= 0,us= 0;
class Solution {
public:
	string s;
	
    int minCut(string s) {
        if(!s.size())return 0;
		this->s = s;
		int len = s.size();
		
		for(int i = 0; i < len; i++)
			for(int j = 0; j < len; j++)
				dp[i][j] = -1;

		return cut(0,len - 1);
    }

	int cut(int l, int r)
	{c++;
		if(dp[l][r] != -1)return dp[l][r];
		us++;
		int midlen = (r - l + 1) / 2 ,i;
		for(i = 0; i < midlen; i++)
		{
			if(s[l + i] != s[r - i])break;
		}
		if(i == midlen)
		{
			dp[l][r] = 0;
			return 0;
		}

		int rst = r - l;
		for(int k = l; k < r; k++)
		{
			int lcut = cut(l, k);
			int rcut = cut(k + 1, r);
			rst = min(rst, lcut + rcut + 1);
		}
		dp[l][r] = rst;
		return rst;


	}
};


 

AC代码:

const int MAX = 20000+ 5;
int dp[MAX];
class Solution {
public:
	string s;
	
	void generate_pal_vector(vector<vector<int> > &symt)
	{
		vector<int> v;
		for(int i = 0; i < s.size(); i++)
		{
			v.clear();
			v.push_back(i);//单个字符s[i]也是回文串

			//有 i- 1操作的注意左边界
			if(i > 0 && s[i] == s[i - 1])v.push_back(i - 1);

			if(i > 0)
			for(int k = 0; k < symt[i - 1].size(); k++)
			{
				if(symt[i - 1][k] > 0 && s[i] == s[symt[i - 1][k] - 1])
					v.push_back(symt[i - 1][k] - 1);
			}
			symt.push_back(v);
		}
	}

    int minCut(string s) {
        if(!s.size())return 0;
		this->s = s;
		int len = s.size();
		
		vector<vector<int> > symt;

		generate_pal_vector(symt);

		dp[0] = -1;
		//计算dp[i]的最优解
		for(int i = 1; i <= len; i++)
		{
			//最坏为 i - 1种切法
			int rst = i - 1;
			//遍历i之前与i组成回文串的所有下标k,更新最小值
			for(int k = 0; k < symt[i - 1].size(); k++)
			{
				int idx = symt[i - 1][k];
				if(s[i - 1] == s[idx])
				{
					rst = min(rst, dp[idx] + 1);
				}
			}
			dp[i] = rst;
		}

		return dp[len];
    }
	
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值