可能性展开的常见方式
1 基于两侧端点讨论的可能性展开
2 基于范围上划分点的可能性展开

题目一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
package class076;

// 让字符串成为回文串的最少插入次数
// 给你一个字符串 s
// 每一次操作你都可以在字符串的任意位置插入任意字符
// 请你返回让s成为回文串的最少操作次数
// 测试链接 : https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/
// 严格位置依赖的动态规划
public static int minInsertions(String str) {
char[] s = str.toCharArray();
int n = s.length;
int[][] dp = new int[n][n];
for (int l = 0; l < n - 1; l++) {
dp[l][l + 1] = s[l] == s[l + 1] ? 0 : 1;
}
for (int l = n - 3; l >= 0; l--) {
for (int r = l + 2; r < n; r++) {
if (s[l] == s[r]) {
dp[l][r] = dp[l + 1][r - 1];
} else {
dp[l][r] = Math.min(dp[l][r - 1], dp[l + 1][r]) + 1;
}
}
}
return dp[0][n - 1];
}
}

题目二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package class076;

// 预测赢家
// 给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏
// 玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手
// 开始时,两个玩家的初始分值都是 0
// 每一回合,玩家从数组的任意一端取一个数字
// 取到的数字将会从数组中移除,数组长度减1
// 玩家选中的数字将会加到他的得分上
// 当数组中没有剩余数字可取时游戏结束
// 如果玩家 1 能成为赢家,返回 true
// 如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true
// 你可以假设每个玩家的玩法都会使他的分数最大化
// 测试链接 : https://leetcode.cn/problems/predict-the-winner/

题目三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package class076;

// 多边形三角剖分的最低得分
// 你有一个凸的 n 边形,其每个顶点都有一个整数值
// 给定一个整数数组values,其中values[i]是第i个顶点的值(顺时针顺序)
// 假设将多边形 剖分 为 n - 2 个三角形
// 对于每个三角形,该三角形的值是顶点标记的乘积
// 三角剖分的分数是进行三角剖分后所有 n - 2 个三角形的值之和
// 返回 多边形进行三角剖分后可以得到的最低分
// 测试链接 : https://leetcode.cn/problems/minimum-score-triangulation-of-polygon/
// 严格位置依赖的动态规划
public static int minScoreTriangulation2(int[] arr) {
int n = arr.length;
int[][] dp = new int[n][n];
for (int l = n - 3; l >= 0; l--) {
for (int r = l + 2; r < n; r++) {
dp[l][r] = Integer.MAX_VALUE;
for (int m = l + 1; m < r; m++) {
dp[l][r] = Math.min(dp[l][r], dp[l][m] + dp[m][r] + arr[l] * arr[m] * arr[r]);
}
}
}
return dp[0][n - 1];
}