BUGAWAY算法小抄-时间开销为O(k^n)的一类动态规划问题
131. 分割回文串
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串。返回 s
所有可能的分割方案。
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a"
输出:[["a"]]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成
✏️ 题解
class Solution {
private List<List<String>> res = new ArrayList<>();
public List<List<String>> partition(String s) {
// k^n的动态规划问题
// 回溯 + 动态规划预处理
// 动态规划预处理的是回文串(动规预处理这里有点难,要思考一下)
// dp[i][j]表示字符串 s[i...j]是否是回文
// dp[i][j] = true when i >= j
// dp[i][j] = (s[i] == s[j]) && dp[i+1][j-1]
int n = s.length();
boolean[][] dp = new boolean[n][n];
// 初始化
for (int i = 0; i < n; i++) {
Arrays.fill(dp[i], true);
}
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
dp[i][j] = (s.charAt(i) == s.charAt(j)) && dp[i + 1][j - 1];
}
}
dfs(s, 0, new ArrayList<String>(), dp);
return res;
}
// public boolean isPalindrome(String s) {
// // 双指针常见做法判断字符串是否是回文串
// // 在该题的缺点是容易重复判断
// // if (s.length() == 0 || s.length() == 1)
// // return true;
// // int i = 0, j = s.length() - 1;
// // while (i < j) {
// // if (s.charAt(i) != s.charAt(j))
// // return false;
// // i++;
// // j--;
// // }
// // return true;
// }
public void dfs(String s, int i, List<String> ans, boolean[][] dp) {
int n = s.length();
if (i == n) {
res.add(new ArrayList<String>(ans));
return;
} else {
for (int j = i; j < n; j++) {
if (dp[i][j]) {
ans.add(s.substring(i, j + 1));
dfs(s, j + 1, ans, dp);
ans.remove(ans.size() - 1);
}
}
}
}
}
787. K 站中转内最便宜的航班
有 n
个城市通过一些航班连接。给你一个数组 flights
,其中 flights[i] = [fromi, toi, pricei]
,表示该航班都从城市 fromi
开始,以价格 pricei
抵达 toi
。
现在给定所有的城市和航班,以及出发城市 src
和目的地 dst
,你的任务是找到出一条最多经过 k
站中转的路线,使得从 src
到 dst
的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1
。
示例 1:
输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200
解释:
城市航班图如下
从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。
示例 2:
输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解释:
城市航班图如下
从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500,如图中蓝色所示。
提示:
1 <= n <= 100
0 <= flights.length <= (n * (n - 1) / 2)
flights[i].length == 3
0 <= fromi, toi < n
fromi != toi
1 <= pricei <= 104
- 航班没有重复,且不存在自环
0 <= src, dst, k < n
src != dst
🐧 腾讯 2024 技术岗春招笔试第四题
小红拿到了一个数组,她准备将数组分割成 k 段,使得每段内部做按位异或后,再全部求和。小红希望最终这个和尽可能大,你能帮帮她吗?
示例 1:
输入:arr = [1,1,1,2,3,4], k=2
输出:10
说明:分割方式:[1,1,1,2 | 3,4]
这道题和上面的有异曲同工之妙。(因为是笔试真题,没找到所有原题样例,只记得一个样例)
import java.util.Scanner;
public class Demo84 {
// 动态规划 f[i][cnt] 表示[i, n-1]分割 k-cnt 段能产生的最大和 return f[0][0]
// 初始化最后一排为0,最后一列为0 内外层都是从后往前遍历
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int[] arr = new int[n];
int[] sum = new int[n + 1]; // 异或前缀和
for (int i = 0; i < n; i++) {
arr[i] = in.nextInt();
sum[i + 1] = sum[i] ^ arr[i];
}
long[][] f = new long[n + 1][k + 1];
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
for (int s = 1; s <= k; s++) {
f[i][s] = max(f[i][s], f[j][s - 1] + (sum[i + 1] ^ sum[j + 1]));
}
}
}
System.out.println(f[0][0]);
}
}