本文正在参加「Java主题月 - Java 刷题打卡」,详情查看<活动链接>
【Java 刷题打卡 】刷题比玩游戏好多了,成就感越来越强,每天坚持刷几道题,每天锻炼30分钟,等8块腹肌,等大厂offer.
那就干吧! 这个专栏都是刷的题目都是关于动态规划的,我会由浅入深、循序渐进,刷题就是这样需要连续不断的记忆--艾宾浩斯记忆法2121112。动态规划的内容不多,但是都是每个程序员必备的
什么题可以选择动态规划来做?
1.计数
- 有多少种方式走到右下角
- 有多少种方法选出k个数是的和是sum
2.求最大值最小值
- 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
3.求存在性
- 取石子游戏,先手是否必胜
- 能不能选出k个数使得和是sum
leecode 132. 分割回文串 II
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
示例 1:
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
示例 2:
输入:s = "a"
输出:0
示例 3:
输入:s = "ab"
输出:1
提示:
1 <= s.length <= 2000
s 仅由小写英文字母组成
--
这道题跟前面有道最长回文串右相似之处,可以参考一下~~~ ❤️❤️❤️❤️
2.1. 动态规划组成部分1:确定状态
简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么,类似数学题中x, y, z代表什么
最后一步
我们可以同之前的方式判断出所有字符可能组成的字符串。直达
我们用如下示例来讲解,下图是第一步和第二步的判断过程,很明显最后一步为下标为4的字母b与前面所有元素进行比较,得出最长的回文子串。
子问题
我们可以看到如果f[i] =f[j],要判定它是一个回文串,需要判定
f[i]j] = f[i+1]f[j-1] : 从i到j是一个回文串,那么从i+1到j-1一定也是一个回文串
也就是如上图需要判定a=a
1.2. 动态规划组成部分2:转移方程
对于从i到j长度的字符串,判定它是一个回文串:
f[i]j] = f[i+1]f[j-1]
同时我们也知道,f[i+1][j-1]这是一个已知的,因为最后一步的上一步已经将结果保存,也就是f[i+1][j-1] = f[i+2]f[j-2]
1.3. 动态规划组成部分3:初始条件和边界情况
当剩余判定字母个数<3 并且 f[i] = f[j],它一定是回文串。
对于字母本身来说f[i][i],从i到i的字符串,它也是回文。
1.4. 动态规划组成部分4:计算顺序
如上图,我们用j去匹配0~i (i < j)
同样正序遍历i和j, 如果f[0][i] = true(是回文)的话不需要分割,否者是需要分割的,我们用i去遍历每个j
如果是回文,我们就记录min{f[i],f[j]+1}
例如字符串:"cdd", 最小1次就行了,在用第二个字母d去遍历c,d,d 三个字符时,在遍历第一个d是回文f[1][2]需要f[2] = 0+1次,遍历第二个d是f[2][2],f[j] + 1 = 2次,所以,会得出min{f[i],f[j]+1}
参考代码
java版
class Solution {
boolean[][] dp;
List<List<String>> ret = new ArrayList<List<String>>();
List<String> ans = new ArrayList<String>();
int n;
public List<List<String>> partition(String s) {
n = s.length();
dp = new boolean[n][n];
char[] charArray = s.toCharArray();
for (int i = 0; i < n; i++) {
dp[i][i] = true; // 对本身来说就是回文
}
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1]; // 要满足这个条件,必需先满足j - i > 3考虑边界
}
}
}
}
int[] f = new int[n];
Arrays.fill(f, Integer.MAX_VALUE);
for (int i = 0; i < n; ++i) {
if (g[0][i]) {
f[i] = 0;
} else {
for (int j = 0; j < i; ++j) {
if (g[j + 1][i]) { // j+ 1的原因是,不用从0开始,我们已经判断了f[0][i]了
f[i] = Math.min(f[i], f[j] + 1); // 这里请看上面说明。
}
}
}
}
return f[n - 1];
}
}
真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话
求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!
如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️