【palindrome partitioning II】cpp

题目:

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.

代码:

class Solution {
public:
        int minCut(string s)
        {
            const int len = s.size();
            vector<vector<bool> > p(len, vector<bool>(len,false));
            Solution::allPalindrome(p, s);
            vector<int> dp(len, INT_MAX);
            dp[0] = 0;
            for ( int i = 1; i < len; ++i )
            {
                for ( int j = i; j >= 1; --j )
                {
                    if ( j==1 )
                    {
                        if ( p[j-1][i] )
                        {
                            dp[i] = 0;
                            break;
                        }
                    }
                    if ( p[j][i] )
                    {
                        dp[i] = std::min(dp[i], dp[j-1]+1);
                    }
                }
            }
            return dp[len-1];
        }
        // palindromes[i][j] denotes if s[i:j] is palindrome
        static void allPalindrome(vector<vector<bool> >& palindromes, string& s)
        {
            for ( int i = palindromes.size()-1; i >=0 ; --i )
            {
                for ( int j = i; j <= palindromes.size()-1; ++j )
                {
                    if ( (i+1>j-1 && s[i]==s[j]) || (i+1<=j-1 && s[i]==s[j] && palindromes[i+1][j-1]) )
                    {
                        palindromes[i][j] = true;
                    }
                }
            }
        }
};

tips:

通过此题掌握了动态规划的一些套路。

动规的核心在于求解两个重要的变量

p[i][j] : 代表s[i]到s[j]是否构成一个回文

dp[i] : 标记s[0]到s[i]的最小回文分割

接下来阐述上述两个变量的生成过程:

1. p[i][j]

正确地求出p[i][j]就是成功的一半,第一次没有AC主要就是p[i][j]求错了。在这里详细记录一下正确的求解过程

第一步,要明确p[i][j]的含义,即s[i]到s[j]是否为回文。

第二步,把求解p[i][j]转化为状态转移方程,即p[i][j] = f(p[k][v]) (k<=i, v<=j, 且k==i,v==j不同时成立)。

这个看起来是一个二维的dp方程,条件什么的比较麻烦,但实际上方程比较简单。

p[i][j] = s[i]==s[j] && p[i+1][j-1]

相当于两个条件

a) 首尾相等

b) 中间子字符串是回文

当然,还要处理一些极端情况:

极端情况1:i==j

极端情况2:i==j+1

把极端的case处理好,就可以开始dp过程了

另,因为是回文(正反都一样)所以求解p的时候,只用求解上三角阵就可以了。

2. dp[i]

之前理解dp有一个误区:认为dp[i]由dp[i-1]一步推倒过来。这是非常不正确的。

正确的理念应该是:dp[i]应该由dp[0]~dp[i-1]导出。(即当前结受到已计算出的中间结果影响,只不过有时候用不到回溯那么靠前的中间结果,只用回溯上一步的结果dp[i-1]就可以了

然而,这道题正好不能只回溯一步,而是要回溯所有之前步骤。

既然要回溯,就要有规则,规则要保证不重不漏。这里我们关注的点是s[i]:即,我们求dp[i]则s[i]是一定要包含在其中某个回文字串中的,具体如下:

s[i]自己是一个回文子串

s[i-1:i]构成回文子串

s[i-2:i]构成回文子串

...

s[0:i]构成回文串

上述的i+1种情况如果都讨论到了,则dp[i]也就求出来了。

具体阐述如下:

s[0] ... s[i-2] s[i-1] s[i]:如果p[i-1][i]==true (即s[i-1]~s[i]是回文),则如果切割点在s[i-2]与s[i-1]之间,则dp[i] = min ( dp[i] , dp[i-2]+1)

....

s[0] ... s[j-1] s[j] ... s[i]:如果p[j][i]==true,则如果切割点在dp[i] = min ( dp[i], dp[j-1]+1)

s[0] ... s[i] :如果p[0][i]==true,则不用切割也可以,故最小切割数是0。

按照上述的思路,再处理一下corner case,代码也就出来了。

=====================================

这份代码在处理corner cases上面做的不太好,有很多可以避免的冗余。但是先保留着吧,毕竟是原始的思考思路。第二遍刷的时候,再精细化一些corner case。

时间: 2024-10-25 15:30:02

【palindrome partitioning II】cpp的相关文章

【Unique Paths II】cpp

题目: Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid. For example, There is one obstacle in the m

【Word Break II】cpp

题目: Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences. For example, givens = "catsanddog",dict = ["cat", "cats&q

【Jump Game II 】cpp

题目: Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Your goal is to reach the last index in the minimum number of j

【Path Sum II】cpp

题目: Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. For example:Given the below binary tree and sum = 22, 5 / 4 8 / / 11 13 4 / \ / 7 2 5 1 return [ [5,4,11,2], [5,8,4,5] ] 代码: /** * Definition f

【Spiral Matrix II】cpp

题目: Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. For example,Given n = 3, You should return the following matrix: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 代码: class Solution { public: vector<vector<

【Single Num II】cpp

题目: Given an array of integers, every element appears three times except for one. Find that single one. Note:Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 代码: class Solution { public: int s

【LeetCode】Palindrome Partitioning II

Palindrome Partitioning II  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 p

【Pascal&#39;s Triangle II 】cpp

题目: Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return [1,3,3,1]. Note:Could you optimize your algorithm to use only O(k) extra space? 代码: class Solution { public: vector<int> getRow(int rowIndex) { vector

LeetCode: Palindrome Partitioning II [132]

[题目] 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&