【动态规划】回文串(二)

📝前言说明:

  • 本专栏主要记录本人的动态规划算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础python入门基础C++学习笔记Linux
🎀CSDN主页 愚润泽

你可以点击下方链接,进行不同专题的动态规划的学习

点击链接开始学习
斐波那契数列模型路径问题
简单多状态(一)简单多状态(二)
子数组系列(一)子数组系列(二)
子序列问题(一)子序列问题(二)
回文串(一)回文串(二)
两个数组dp问题(一)两个数组的dp问题(二)
01背包问题完全背包
二维的背包问题其他

题单汇总链接:点击 → 题单汇总


132. 分割回文串 II

题目链接:https://leetcode.cn/problems/palindrome-partitioning-ii/description/
在这里插入图片描述


优质解

思路:

  • 对表示是否是回文子串的 isPal 数组再做一次 dp
  • dp[i]: s[0 - i] 中要分割的最少次数
  • 我们可以把串分成:[0 - j-1][j - i],而 dp[j - 1] 可以表示以 j - 1 结尾的子串分割的最小次数(已知)
  • 所以 j 遍历:1 <= j <= i,
    • 如果 [j - i] 可以构成回文串: dp[i] = dp[j - 1] + 1,
    • 不能构成: 跳过(迟早到 i == j 的时候会构成回文)
    • 取循环中得到的 dp[i] 的最小值

代码:

class Solution {
public:
    int minCut(string s) 
    {
        int n = s.size();
        vector<vector<bool>> isPal(n, vector<bool>(n, 0));
        for(int i = n - 1; i >= 0; i--)
        {
            for(int j = i; j < n; j++)
            {
                if(s[i] == s[j])
                    isPal[i][j] = i + 1 < j ? isPal[i + 1][j - 1] : true;
            }
        }

        // 对 isPal 做 dp
        vector<int> dp(n, INT_MAX / 2);
        for(int i = 0; i < n; i++)
        {
            if(isPal[0][i]) dp[i] = 0; // 判断 0 - i
            else
            {
                for(int j = 1; j <= i; j++)
                {
                    if(isPal[j][i])
                        dp[i] = min(dp[i], dp[j - 1] + 1);
                }
            }
        }
        return dp[n - 1];
    }
};

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2)


516. 最长回文子序列

题目链接:https://leetcode.cn/problems/longest-palindromic-subsequence/description/
在这里插入图片描述


优质解

思路

状态表示

  • dp[i][j]: [i, j]区间内的所有子序列中,最长的回文子序列

状态转移方程

  • if s[i] == s[j], 那 dp[i][j] = dp[i + 1][j - 1] + 1;
    • 无效区间(越界), i + 1 < j : dp[i][i] = 字符个数;
  • if s[i] != s[j] (代表两端不会同时对构成回文子序列有帮助)
    • 去[i + 1, j] 和 [i, j - 1] 两个区间找: max(dp[i][j - 1], dp[i + 1][j]);

初始化:

  • 发现只有[0][0][i - 1][i - 1] 会越界(但是状态转移方程已经处理了)
    填表顺序

填表顺序

  • 看状态转移需要什么位置的 dp 值
    • 整体行: 从下到上(因为需要 i - 1),
    • 每一行内部: 从左往右(因为要 j - 1)

返回值

  • dp[0][n - 1];

代码:

class Solution {
public:
    int longestPalindromeSubseq(string s) 
    {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n, 0));
        for(int i = n - 1; i >= 0; i--)
        {
            dp[i][i] = 1; // 初始化
            for(int j = i + 1; j < n; j++) // 枚举右端
            {
                if(s[i] == s[j])
                    dp[i][j] = i + 1 == j ? 2 : dp[i + 1][j - 1] + 2;
                else dp[i][j] = max(dp[i][j - 1], dp[i + 1][j]);
            }
        }
        return dp[0][n - 1];
    }
};

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2)


1312. 让字符串成为回文串的最少插入次数

题目链接:https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/description/
在这里插入图片描述


优质解

思路:

  • 总体思路和上一题都差不多
  • 状态表示:dp[i][j][i, j]区间的子串,成为回文串的最小插入次数
  • 状态转移方程:s[i] == s[j]...不多说了,s[i] != s[j]...
  • 细节问题不说了

代码:

class Solution {
public:
    int minInsertions(string s) 
    {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n, INT_MAX));
        for(int i = n - 1; i >= 0; i--)
        {
            dp[i][i] = 0;
            for(int j = i + 1; j < n; j++)
            {
                if(s[i] == s[j])
                    dp[i][j] = i + 1 == j? 0 : dp[i + 1][j - 1];
                else
                    dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1;
            }
        }
        return dp[0][n - 1];
    }
};

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2)


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚润泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值