[leetcode]Palindrome Partitioning II

14 篇文章 0 订阅

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 partitioning ["aa","b"] could be produced using 1 cut.

解题思路:先求出所有可能的回文串一次动态规划,然后在此基础上二次用动态规划求出最小分割次数

比较类似矩阵连乘问题,但是O(n^3)的复杂度会导致超时。

解法一超时

class Solution {
public:
    //判断字符串s [b,e]是不是回文
    bool isPalindrome(string &s, size_t b, size_t e){
        while(b < e){
            if(s[b] != s[e]) return false;
            b++; e--;
        }
        return true;
    }

    int minCut(string s) {
        size_t n = s.size();
        vector<vector<bool> > vvi(n, vector<bool>(n, false));
        //动态规划 vvi[i, j]表示从i到j是回文串 此处的时间复杂度O(n^3)所以超果
        for(int i = 0; i < n; i++){ 
            for(int j = i; j < n; j++){
                vvi[i][j] = isPalindrome(s, i, j); //这里需要优化
            }
        }
        
        vector<int> vi(n,  0);
        //二次动态规划
        for(int i = 1; i < n; i++){
            if(vvi[0][i]){
                continue; //如果是回文串直接跳过
            }
            int tmpn = n;
            //找出以j为分割点的所有最小划分
            for(int j = 0; j < i; j++){
                if(vvi[j + 1][i]){
                    tmpn = min(tmpn, vi[j] + 1); //如果vvi[j+1][i]是回文串
                }else{//如果不是
                    tmpn = min(tmpn, vi[j] + i - j);
                }
            }
            vi[i] = tmpn;
        }
        
        return vi[n - 1];
    }
};
针对解法一中需要优化的地方,要对求回文串也使用动态规划的方法
dp[i][j]表示从i到j的字符,包括i,j是回文串,如图所示

dp[i][j] = true; if(s[i] == s[j] && j - i < 2)
dp[i][j] = true; if(s[i] == s[j] && dp[i + 1][j - 1])
第二个表达式是一种递归的定义,如果s[i] s[j]相等,那么s[i + 1] 至s[j - 1]如果是回文即dp[i + 1][j - 1]为真则dp[i+1][j-1]为真
而对于最小切分也是一种动态规划
v[i]表示从0到i的最小切分次数
v[i] = min(v[k] + 1/* 0<= k < i, s[k + 1]至s[i]是回文串*/, v[k] + i - k/*s[k+1] 至s[i]不是回文串*/)
class Solution {
public:
    int minCut(string s) {
        size_t n = s.size();
        vector<vector<bool> > vvi(n, vector<bool>(n, false));
        //动态规划 vvi[i, j]表示从i到j是回文串
        for(int i = n - 1; i >= 0; i--){
            for(int j = i; j < n; j++){
                if(s[i] == s[j] &&(j - i < 2 || vvi[i + 1][j - 1])){
                    vvi[i][j] = true;
                }
            }
        }
        vector<int> vi(n,  0);

        for(int i = 1; i < n; i++){ //动态规划找最小划分次数
            if(vvi[0][i]){
                continue; //如果是回文串直接跳过
            }
            int tmpn = n;
            //找出以j为分割点的所有最小划分
            for(int j = 0; j < i; j++){
                if(vvi[j + 1][i]){
                    tmpn = min(tmpn, vi[j] + 1); //如果vvi[j+1][i]是回文串
                }else{//如果不是
                    tmpn = min(tmpn, vi[j] + i - j);
                }
            }
            vi[i] = tmpn;
        }
        
        return vi[n - 1];
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值