📝前言说明:
- 本专栏主要记录本人的动态规划算法学习以及LeetCode刷题记录,按专题划分
- 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
- 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽
你可以点击下方链接,进行不同专题的动态规划的学习
点击链接 | 开始学习 |
---|---|
斐波那契数列模型 | 路径问题 |
简单多状态(一) | 简单多状态(二) |
子数组系列(一) | 子数组系列(二) |
子序列问题(一) | 子序列问题(二) |
回文串(一) | 回文串(二) |
两个数组dp问题(一) | 两个数组的dp问题(二) |
01背包问题 | 完全背包 |
二维的背包问题 | 其他 |
题单汇总链接:点击 → 题单汇总
题目
- 132. 分割回文串 II
- 优质解
- 516. 最长回文子序列
- 优质解
- 1312. 让字符串成为回文串的最少插入次数
- 优质解
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 做 dpvector<int> dp(n, INT_MAX / 2);for(int i = 0; i < n; i++){if(isPal[0][i]) dp[i] = 0; // 判断 0 - ielse{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];elsedp[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)
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!