您的位置:首页 > 编程语言 > C语言/C++

LeetCode 132. Palindrome Partitioning II (C++)

2016-01-25 23:36 375 查看
题目描述

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.

解题思路

首先想到的是动态规划,其次想想可否暴力求解。但是动态规划的题用暴力求解通常会超时或者超内存,事实上我在做的时候,复杂度高的动态规划仍然会超时。这道题的测试用例确实很棒,对算法复杂度要求很高。下面先从高复杂的的代码说起,逐步得到“正确”的代码。

解法一(超时):二维动归+遍历

求回文串:逆序判断等(非动态规划)

求切割数:s的子串s(i,j): s[i]…s[k-1] | s[k]…s[j]

从s[k-1]和s[k]之间分割为两部分,则s(i,j)如果不是回文串,则其最小分割的就是找一个合适的k,并在k处分割。这个合适的k需要在i到j直接遍历寻找,这就是动态规划中的遍历操作。递归方程如下:

f(i,j) = min { f(i,k-1) + f(k,j) } if s(i,j)不是回文

f(i,j) = 0 if s(i,j)是回文

上式中,s(i,j)表示s的从i到j的子串,f(i,j)表示子串s(i,j)的最小切割数。注意递归式中等式的左边有两个参数,说明是需要二维动态规划,等式右边有min求最小值,说明需要遍历,此即为二维动归+遍历,代码非常容易写。

复杂度为O(n^3)

class Solution {
public:
int minCut(string s) {
int n=s.length();
//二维数组,初值设为0,多增加一个空间,以防越界
vector<vector<int> > f(n+1,vector<int>(n+1,0));
//以子串长度为递归条件
for(int l=2;l<=n;l++)
{
for(int i=0;i<=n-l;i++)
{
int j=i+l-1;
//求字符串是否为回文串
string s1=s.substr(i,l);//i为起始位置,l为长度
string s2(s1.rbegin(),s1.rend());//构造逆序串
if(s1==s2)f[i][j]=0;
//如果不是回文串则遍历求最小切割数
else
{
f[i][j]=n;//初始化为最大值
for(int k=i+1;k<=j;k++)//注意作开右闭
f[i][j]=min(f[i][j],f[i][k-1]+f[k][j]+1) ;
}
}
}
return f[0][n-1];//从0开始
}
};


解法二(Accept):

求回文串:动态规划

s(i,j)为回文串,当且仅当s[i]=s[j],并且s(i+1,j-1)是回文串。用递推方程表示为:d(i,j)=true , if s[i]=s[j]&&s(i+1,j-1)是回文串。

求切割数:一维动归+备忘录

备忘录就是提前将s(i,j)是否为回文串记录在一个数组中,供动态规划查找。

动态规划采用一维+遍历方式,递推方程如下:

f(j)=min{f(j),f(i-1)+1} ,0<=i<=j,并且s(0,j)不是回文串

f(j)=0 if s(0,j)是回文串

f(j)表示s(0,j)的最小切割数。

s的子串s(0,j) : s[0]…s[i-1] | s[i]…s[j]

时间复杂度O(n^2).

class Solution {
public:
int minCut(string s) {
int n=s.length();
//回文字串备忘录,记录是子串是否为回文串,初值为false
vector<vector<bool> > p(n+1,vector<bool>(n+1,false));
for(int j=0;j<n;j++)
{
for(int i=j;i>=0;i--)
p[i][j]=p[i][j]||(s[i]==s[j]&&(j-i<=1||p[i+1][j-1]));
}

vector<int> f(n+1,0);
for(int i=0;i<n;i++) f[i]=i;
for(int j=0;j<n;j++)//正序递归
{
for(int i=j;i>=0;i--)//逆序递归
{
if(p[i][j])
{
if(i==0) f[j]=0;
else f[j]=min(f[j],f[i-1]+1);
}
}
}
return f[n-1];
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 动态规划 string