文章目录
- **`dp`**
- eg.1. [斐波那契数列](https://leetcode.cn/problems/fibonacci-number/)
- eg.2. [恰好移动 k 步到达某一位置的方法数目](https://leetcode.cn/problems/number-of-ways-to-reach-a-position-after-exactly-k-steps/)
- eg.3. [预测赢家](https://leetcode.cn/problems/predict-the-winner/)
- eg.4. 背包问题
- eg.5. 字符串转换
- eg.6. [贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/)
- eg.7. [最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/)
- eg.8. [最长回文子序列](https://leetcode.cn/problems/longest-palindromic-subsequence/)
dp
eg.1. 斐波那契数列
public class p1_斐波那契数列 {
private static final int CNT = 10;
public static void main(String[] args) {
System.out.println(f1(CNT));
int[] dp = new int[CNT + 1];
dp[1] = 1;
dp[2] = 1;
System.out.println(f2(CNT, dp));
System.out.println(f3(CNT));
System.out.println(f4(CNT));
}
}
1. 暴力递归
// 暴力递归
private static int f1(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 1;
}
// f(n) = f(n - 1) + f(n - 2);
return f1(n - 1) + f1(n - 2);
}
2. 递归 + 记忆化搜索
private static int f2(int n, int[] dp) {
if (dp[n] != 0) {
return dp[n];
}
if (n < 3) {
return dp[n];
}
dp[n] = f2(n - 1, dp) + f2(n - 2, dp);
// f(n) = f(n - 1) + f(n - 2);
return dp[n];
}
3. dp
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
v | - | 1 | 1 | - | - | - | - | - | - | - | ? |
dp[3] = dp[2] + dp[1];
dp[4] = dp[3] + dp[2];
……
dp[10] = dp[9] + dp[8];
private static int f3(int n) {
if (n < 3) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 1;
for (int i = 3; i <= n; i ++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
4. 优化空间
private static int f4(int n) {
int a = 1;
int b = 0;
int temp = 0;
for (int i = 1; i < n; i ++) {
temp = a;
a += b;
b = temp;
}
return a;
}
eg.2. 恰好移动 k 步到达某一位置的方法数目
力扣里边多了偏移量,大差不差,影响不大hhhh
public class p2_恰好移动k步到达某一位置的方法数目 {
public static void main(String[] args) {
// 14
System.out.println(way3(7, 2, 4, 6));
}
}
1. 暴力递归
/**
* @description: 暴力递归
* @param N -> 1 - N 个数
* @param start -> 开始位置
* @param aim -> 目标位置
* @param K -> 步数
* @return int
* @date: 2022/9/28 2:55
*/
private static int way1(int N, int start, int aim, int K) {
return process1(N, start, aim, K);
}
private static int process1(int N, int cur, int aim, int rest) {
if (rest == 0) {
return cur == aim ? 1 : 0;
}
if (cur == 1) {
return process1(N, cur + 1, aim, rest - 1);
}
if (cur == N) {
return process1(N, cur - 1, aim, rest - 1);
}
return process1(N, cur - 1, aim, rest - 1) + process1(N, cur + 1, aim, rest - 1);
}
2. 递归 + 记忆化搜索
/**
* @description: 递归 + 记忆化搜索
* @param N -> 1 - N 个数
* @param start -> 开始位置
* @param aim -> 目标位置
* @param K -> 步数
* @return int
* @date: 2022/9/28 3:21
*/
private static int way2(int N, int start, int aim, int K) {
int[][] dp = new int[N + 1][K + 1];
Arrays.stream(dp).forEach(arr -> Arrays.fill(arr, -1));
return process2(N, start, aim, K, dp);
}
private static int process2(int N, int cur, int aim, int rest, int[][] dp) {
if (dp[cur][rest] != -1) {
return dp[cur][rest];
}
if (rest == 0) {
dp[cur][rest] = cur == aim ? 1 : 0;
} else if (cur == 1) {
dp[cur][rest] = process2(N, cur + 1, aim, rest - 1, dp);
} else if (cur == N) {
dp[cur][rest] = process2(N, cur - 1, aim, rest - 1, dp);
} else {
dp[cur][rest] = process2(N, cur - 1, aim, rest - 1, dp) + process2(N, cur + 1, aim, rest - 1, dp);
}
return dp[cur][rest];
}
3. dp
eg. N -> 7
start -> 2
aim -> 4
K -> 6dp[j][i] = dp[j - 1][i - 1] + dp[j + 1][i - 1];
cur | rest | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
0 | - | - | - | - | - | - | - |
1 | 0 | 0 | 0 | 1 | 0 | 4 | 0 |
2 | 0 | 0 | 1 | 0 | 4 | 0 | ?(14) |
3 | 0 | 1 | 0 | 3 | 0 | 10 | 0 |
4 | 1 | 0 | 2 | 0 | 6 | 0 | 20 |
5 | 0 | 1 | 0 | 3 | 0 | 10 | 0 |
6 | 0 | 0 | 1 | 0 | 4 | 0 | 14 |
7 | 0 | 0 | 0 | 1 | 0 | 4 | 0 |
/**
* @description: dp
* @param N
* @param start
* @param aim
* @param K
* @return int
* @date: 2022/9/28 4:06
*/
private static int way3(int N, int start, int aim, int K) {
int[][] dp = new int[N + 1][K + 1];
dp[aim][0] = 1;
for (int i = 1; i <= K; i ++) {
dp[1][i] = dp[2][i - 1];
for (int j = 1; j < N; j ++) {
dp[j][i] = dp[j - 1][i - 1] + dp[j + 1][i - 1];
}
dp[N][i] = dp[N - 1][i - 1];
}
return dp[start][K];
}
eg.3. 预测赢家
public class p3_预测赢家 {
public static void main(String[] args) {
// 234
int[] arr = new int[]{1, 5, 233, 7};
System.out.println(win1(arr));
System.out.println(win2(arr));
}
}
1. 暴力递归
/**
* @description:
* @param arr
* @return int 获胜者的分数
* @date: 2022/9/28 14:20
*/
private static int win1(int[] arr) {
return Math.max(f(arr, 0, arr.length - 1), g(arr, 0, arr.length - 1));
}
/**
* @description:
* @param arr
* @param L
* @param R
* @return int arr[L...R] 先手获得的分数
* @date: 2022/9/28 14:21
*/
private static int f(int[] arr, int L, int R) {
if (L == R) {
return arr[L];
}
return Math.max(arr[L] + g(arr, L + 1, R), arr[R] + g(arr, L, R - 1));
}
/**
* @description:
* @param arr
* @param L
* @param R
* @return int arr[L...R] 后手获得的分数
* @date: 2022/9/28 14:21
*/
private static int g(int[] arr, int L, int R) {
if (L == R) {
return 0;
}
return Math.min(f(arr, L + 1, R), f(arr, L, R - 1));
}
2. 递归 + 记忆化搜索
/**
* @description:
* @param arr
* @return int 获胜者的分数
* @date: 2022/9/28 14:20
*/
private static int win2(int[] arr) {
int len = arr.length;
int[][] fMap = new int[len][len];
int[][] gMap = new int[len][len];
for (int i = 0; i < len; i ++) {
for (int j = 0; j < len; j ++) {
fMap[i][j] = -1;
gMap[i][j] = -1;
}
}
return Math.max(f2(arr, 0, arr.length - 1, fMap, gMap), g2(arr, 0, arr.length - 1, fMap, gMap));
}
/**
* @param arr
* @param L
* @param R
* @param fMap
* @param gMap
* @return int arr[L...R] 先手获得的分数
* @description:
* @date: 2022/9/28 14:21
*/
private static int f2(int[] arr, int L, int R, int[][] fMap, int[][] gMap) {
if (fMap[L][R] != -1) {
return fMap[L][R];
}
if (L == R) {
fMap[L][R] = arr[L];
} else {
fMap[L][R] = Math.max(arr[L] + g2(arr, L + 1, R, fMap, gMap), arr[R] + g2(arr, L, R - 1, fMap, gMap));
}
return fMap[L][R];
}
/**
* @param arr
* @param L
* @param R
* @param fMap
* @param gMap
* @return int arr[L...R] 后手获得的分数
* @description:
* @date: 2022/9/28 14:21
*/
private static int g2(int[] arr, int L, int R, int[][] fMap, int[][] gMap) {
if (gMap[L][R] != -1) {
return gMap[L][R];
}
if (L == R) {
gMap[L][R] = 0;
} else {
gMap[L][R] = Math.min(f2(arr, L + 1, R, fMap, gMap), f2(arr, L, R - 1, fMap, gMap));
}
return gMap[L][R];
}
3. dp
fMap[ ][ ] :
fMap[ i ][ i ] = arr[ i ];
fMap[ L ] [ R ] = Math.max(arr[R] + gMap[ L ][ R - 1 ], arr[ L ] + gMap[ L + 1 ][ R ]);
L | R | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 1 | 5 | 234 | (?)234 |
1 | - | 5 | 233 | 12 |
2 | - | - | 233 | 233 |
3 | - | - | - | 7 |
gMap[ ][ ] :
gfMap[ i ][ i ] = 0;
gMap[ L ] [ R ] = Math.min(fMap[ L ][ R - 1 ], fMap[ L + 1 ][ R ]);
L | R | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0 | 1 | 5 | (?) 12 |
1 | - | 0 | 5 | 233 |
2 | - | - | 0 | 7 |
3 | - | - | - | 0 |
private static int win3(int[] arr) {
int len = arr.length;
int[][] fMap = new int[len][len];
int[][] gMap = new int[len][len];
for (int i = 0; i < len; i ++) {
fMap[i][i] = arr[i];
gMap[i][i] = 0;
}
int start = 0;
while (++ start < len) {
int L = 0;
for (int R = start; R < len; R ++, L ++) {
fMap[L][R] = Math.max(arr[R] + gMap[L][R - 1], arr[L] + gMap[L + 1][R]);
gMap[L][R] = Math.min(fMap[L][R - 1], fMap[L + 1][R]);
}
}
return Math.max(gMap[0][len - 1], fMap[0][len - 1]);
}
eg.4. 背包问题
有 N 件物品和一个最多能背重量为 W 的背包。第 i 件物品的重量是 w[ i ],得到的价值是 v[ i ] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
public class p4_背包问题 {
public static void main(String[] args) {
int[] w = new int[]{3, 2, 4, 7, 3, 1, 7};
int[] v = new int[]{5, 6, 3, 19, 12, 4, 2};
int W = 15;
// 42
System.out.println(maxValue1(w, v, W));
System.out.println(maxValue2(w, v, W));
System.out.println(maxValue3(w, v, W));
}
}
1. 暴力递归
/**
* @description: 暴力递归
* @param w 物品重量
* @param v 物品价值
* @param W 背包能装载的总重量
* @return int 条件允许的情况下, 背包中物品的最大价值
* @date: 2022/9/29 1:58
*/
private static int maxValue1(int[] w, int[] v, int W) {
return process1(w, v, 0, W);
}
/**
* @description:
* @param w 物品重量
* @param v 物品价值
* @param index 当前索引位置
* @param rest 背包剩余容量
* @return int
* @date: 2022/9/29 2:03
*/
private static int process1(int[] w, int[] v, int index, int rest) {
if (rest < 0) {
return -v[index - 1];
}
if (index == w.length) {
return 0;
}
return Math.max(v[index] + process1(w, v, index + 1, rest - w[index]), process1(w, v, index + 1, rest));
}
2. 递归 + 记忆化搜索
/**
* @description: 递归 + 记忆化搜索
* @param w 物品重量
* @param v 物品价值
* @param W 背包能装载的总重量
* @return int 条件允许的情况下, 背包中物品的最大价值
* @date: 2022/9/29 2:25
*/
private static int maxValue2(int[] w, int[] v, int W) {
int[][] dp = new int[w.length][W + 1];
Arrays.stream(dp).forEach(i -> Arrays.fill(i, -1));
return process2(w, v, 0, W, dp);
}
/**
* @description:
* @param w 物品重量
* @param v 物品价值
* @param index 当前索引位置
* @param rest 背包剩余容量
* @param dp index, rest
* @return int
* @date: 2022/9/29 2:25
*/
private static int process2(int[] w, int[] v, int index, int rest, int[][] dp) {
if (rest < 0) {
return -v[index - 1];
}
if (index == w.length) {
return 0;
}
if (dp[index][rest] != -1) {
return dp[index][rest];
}
dp[index][rest] = Math.max(v[index] + process2(w, v, index + 1, rest - w[index], dp), process2(w, v, index + 1, rest, dp));
return dp[index][rest];
}
3. dp
int[ ] w = new int[ ] {1, 1, 1, 1 };
int[ ] v = new int[ ] {1, 4, 5, 2 };
int W = 3;
index | rest | 0 | 1 | 2 | 3 |
---|---|---|---|---|
0 | 0 | 5 | 9 | (?)11 |
1 | 0 | 5 | 9 | 11 |
2 | 0 | 5 | 7 | 7 |
3 | 0 | 2 | 2 | 2 |
4 | 0 | 0 | 0 | 0 |
/**
* @description: dp
* @param w 物品重量
* @param v 物品价值
* @param W 背包能装载的总重量
* @return int 条件允许的情况下, 背包中物品的最大价值
* @date: 2022/9/29 2:26
*/
private static int maxValue3(int[] w, int[] v, int W) {
// dp[index][rest]
// index - 索引位
// rest - 背包剩余容量
int[][] dp = new int[w.length + 1][W + 1];
for (int index = w.length - 1; index > -1; index --) {
for (int rest = 0; rest <= W; rest ++) {
if (rest - w[index] < 0) {
dp[index][rest] = dp[index + 1][rest];
} else {
dp[index][rest] = Math.max(v[index] + dp[index + 1][rest - w[index]], dp[index + 1][rest]);
}
}
}
return dp[0][W];
}
eg.5. 字符串转换
规定1和A对应、2和B对应、3和C对应…那么一个数字字符串比如"111”就可以转化为:'AAA"、 “KA"和"AK”。给定一个只有数字字符组成的字符串str,返回有多少种转化结果 ?
public class p5_字符串转换 {
public static void main(String[] args) {
// 3
System.out.println(f1("2132082"));
// 54
System.out.println(f2("7210231231232031203123"));
// 54
System.out.println(f3("7210231231232031203123"));
}
}
1. 暴力递归
private static int f1 (String str) {
return process1(str.toCharArray(), 0);
}
private static int process1(char[] ch, int index) {
// 方法不错奥 ~
if (index == ch.length) {
return 1;
}
// 之前决定有问题 eg.str = "10"
// 10 -> J
// 1 、0 -> A (0 -> error, 并没有数字对应, 此方法行不通)
if (ch[index] == '0') {
return 0;
}
int cnt = process1(ch, index + 1);
if (index + 1 < ch.length && ((ch[index] - '0') * 10 + ch[index + 1] - '0') < 27) {
cnt += process1(ch, index + 2);
}
return cnt;
}
2. 递归 + 记忆化搜索
private static int f2(String str) {
int[] dp = new int[str.length()];
Arrays.fill(dp, -1);
return process2(str.toCharArray(), 0, dp);
}
private static int process2(char[] ch, int index, int[] dp) {
// 方法不错奥 ~
if (index == ch.length) {
return 1;
}
if (dp[index] != -1) {
return dp[index];
}
// 之前决定有问题 eg.str = "10"
// 10 -> J
// 1 、0 -> A (0 -> error, 并没有数字对应, 此方法行不通)
if (ch[index] == '0') {
return 0;
}
int cnt = process2(ch, index + 1, dp);
if (index + 1 < ch.length && ((ch[index] - '0') * 10 + ch[index + 1] - '0') < 27) {
cnt += process2(ch, index + 2, dp);
}
dp[index] = cnt;
return cnt;
}
3. dp
str = “2132082”
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
cnt | (?)3 | 2 | 1 | 1 | 0 | 1 | 1 | 1 |
private static int f3(String str) {
int[] dp = new int[str.length() + 1];
char[] ch = str.toCharArray();
dp[str.length()] = 1;
for (int index = str.length() - 1; index > -1; index --) {
if (ch[index] != '0') {
dp[index] = dp[index + 1];
if (index + 1 < str.length() && ((ch[index] - '0') * 10 + ch[index + 1] - '0') < 27) {
dp[index] += dp[index + 2];
}
}
}
return dp[0];
}
eg.6. 贴纸拼词
public class p6_贴纸拼词 {
public static void main(String[] args) {
System.out.println(f1(new String[]{"with", "example", "science"}, "thehat"));
System.out.println(f2(new String[]{"with", "example", "science"}, "thehat"));
System.out.println(f3(new String[]{"with", "example", "science"}, "thehat"));
}
}
1. 暴力递归
/**
* @description: 暴力递归
* @param stickers
* @param target
* @return int
* @date: 2022/9/29 6:07
*/
private static int f1(String[] stickers, String target) {
int ans = process1(stickers, target);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
private static int process1(String[] stickers, String target) {
if (target.length() == 0) {
return 0;
}
int min = Integer.MAX_VALUE;
for (String str : stickers) {
// 默认这儿用一张
String rest = minus(target, str);
if (rest.length() != target.length()) {
min = Math.min(min, process1(stickers, rest));
}
}
return min + (min == Integer.MAX_VALUE ? 0 : 1);
}
private static String minus(String target, String str) {
char[] ch1 = target.toCharArray();
char[] ch2 = str.toCharArray();
int[] cnt = new int[26];
for (char c : ch1) {
cnt[c - 'a'] ++;
}
for (char c : ch2) {
cnt[c - 'a'] --;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 26; i ++) {
if (cnt[i] > 0) {
for (int j = 0; j < cnt[i]; j ++) {
builder.append((char) (i + 'a'));
}
}
}
return builder.toString();
}
2. 词频统计 + 剪枝
/**
* @description: 词频统计 + 剪枝
* @param stickers
* @param target
* @return int
* @date: 2022/9/29 6:07
*/
private static int f2(String[] stickers, String target) {
int[][] cnt = new int[stickers.length][26];
for (int i = 0; i < stickers.length; i++) {
char[] ch = stickers[i].toCharArray();
for (char c : ch) {
cnt[i][c - 'a'] ++;
}
}
int ans = process2(cnt, target);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
private static int process2(int[][] s_cnt, String target) {
if (target.length() == 0) {
return 0;
}
char[] t = target.toCharArray();
int[] t_cnt = new int[26];
for (char c : t) {
t_cnt[c - 'a'] ++;
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < s_cnt.length; i ++) {
int[] s = s_cnt[i];
// 剪枝 (重点)
if (s[t[0] - 'a'] > 0) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j < 26; j ++) {
if (t_cnt[j] > 0) {
int nums = t_cnt[j] - s[j];
for (int k = 0; k < nums; k ++) {
builder.append((char) (j + 'a'));
}
}
}
String rest = builder.toString();
min = Math.min(min, process2(s_cnt, rest));
}
}
return min + (min == Integer.MAX_VALUE ? 0 : 1);
}
3. 记忆化搜索
/**
* @description: 记忆化搜索
* @param stickers
* @param target
* @return int
* @date: 2022/9/29 6:08
*/
private static int f3(String[] stickers, String target) {
int[][] cnt = new int[stickers.length][26];
for (int i = 0; i < stickers.length; i++) {
char[] ch = stickers[i].toCharArray();
for (char c : ch) {
cnt[i][c - 'a'] ++;
}
}
Map<String, Integer> dp = new HashMap<>();
int ans = process3(cnt, target, dp);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
private static int process3(int[][] s_cnt, String target, Map<String, Integer> dp) {
if (target.length() == 0) {
return 0;
}
if (dp.containsKey(target)) {
return dp.get(target);
}
char[] t = target.toCharArray();
int[] t_cnt = new int[26];
for (char c : t) {
t_cnt[c - 'a'] ++;
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < s_cnt.length; i ++) {
int[] s = s_cnt[i];
if (s[t[0] - 'a'] > 0) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j < 26; j ++) {
if (t_cnt[j] > 0) {
int nums = t_cnt[j] - s[j];
for (int k = 0; k < nums; k ++) {
builder.append((char) (j + 'a'));
}
}
}
String rest = builder.toString();
min = Math.min(min, process3(s_cnt, rest, dp));
}
}
dp.put(target, min + (min == Integer.MAX_VALUE ? 0 : 1));
return dp.get(target);
}
eg.7. 最长公共子序列
public class p7_最长公共子序列 {
public static void main(String[] args) {
System.out.println(f1("112121231", "3232412"));
System.out.println(f2("112121231", "3232412"));
}
}
1. 暴力递归
/**
* @description: 暴力递归
* @param s1
* @param s2
* @return int
* @date: 2022/9/29 11:42
*/
private static int f1(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
return 0;
}
char[] ch1 = s1.toCharArray();
char[] ch2 = s2.toCharArray();
return process1(ch1, ch2, s1.length() - 1, s2.length() - 1);
}
/**
* @description:
* @param str1
* @param str2
* @param i
* @param j
* @return int ch[0...i] 和 ch2[0...j] 的最长公共序列的长度
* @date: 2022/9/29 8:36
*/
private static int process1(char[] str1, char[] str2, int i, int j) {
if (i == 0 && j == 0) {
return str1[i] == str2[j] ? 1 : 0;
} else if (i == 0) {
if (str1[i] == str2[j]) {
return 1;
} else {
return process1(str1, str2, i, j - 1);
}
} else if (j == 0) {
if (str1[i] == str2[j]) {
return 1;
} else {
return process1(str1, str2, i - 1, j);
}
} else {
int p1 = process1(str1, str2, i - 1, j);
int p2 = process1(str1, str2, i, j - 1);
int p3 = str1[i] == str2[j] ? 1 + process1(str1, str2, i - 1, j - 1) : 0;
return Math.max(p1, Math.max(p2, p3));
}
}
2. dp
/**
* @description: dp
* @param s1
* @param s2
* @return int
* @date: 2022/9/29 11:42
*/
private static int f2(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
return 0;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int M = s1.length();
int N = s2.length();
int[][] dp = new int[M][N];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < N; i ++) {
dp[0][i] = str1[0] == str2[i] ? 1 : dp[0][i - 1];
}
for (int i = 1; i < M; i ++) {
dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
}
for (int i = 1; i < M; i ++) {
for (int j = 1; j < N; j ++) {
int p1 = dp[i - 1][j];
int p2 = dp[i][j - 1];
int p3 = str1[i] == str2[j] ? 1 + dp[i - 1][j - 1] : 0;
dp[i][j] = Math.max(p1, Math.max(p2, p3));
}
}
return dp[M - 1][N - 1];
}
eg.8. 最长回文子序列
public class p8_最长回文子序列 {
public static void main(String[] args) {
System.out.println(f1("1233421"));
}
}
1. 暴力递归
/**
* @description: 暴力递归
* @param str
* @return int
* @date: 2022/9/29 12:46
*/
private static int f1(String str) {
if (str == null || str.length() == 0) {
return 0;
}
return process1(str.toCharArray(), 0, str.length() - 1);
}
/**
* @description:
* @param arr
* @param L
* @param R
* @return int arr[L...R] 上最长回文子序列的长度
* @date: 2022/9/29 12:36
*/
private static int process1(char[] arr, int L, int R) {
if (L == R) {
return 1;
}
if (L + 1 == R) {
return arr[L] == arr[R] ? 2 : 1;
} else if (arr[L] == arr[R]) {
return 2 + process1(arr, L + 1, R - 1);
} else {
return Math.max(process1(arr, L + 1, R), process1(arr, L, R - 1));
}
}
2. dp
“aabaaba”
L | R | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | 2 | 3 | 5 | 5 | 6 |
1 | - | 1 | 1 | 3 | 3 | 4 | 6 |
2 | - | - | 1 | 1 | 4 | 4 | 4 |
3 | - | - | - | 1 | 2 | 2 | 3 |
4 | - | - | - | - | 1 | 1 | 3 |
5 | - | - | - | - | - | 1 | 1 |
6 | - | - | - | - | - | - | 1 |
/**
* @description: dp
* @param str
* @return int
* @date: 2022/9/29 12:46
*/
private static int f2(String str) {
if (str == null || str.length() == 0) {
return 0;
}
char[] arr = str.toCharArray();
int len = arr.length;
int[][] dp = new int[len][len];
for (int i = 0; i < len - 1; i ++) {
dp[i][i] = 1;
dp[i][i + 1] = arr[i] == arr[i + 1] ? 2 : 1;
}
dp[len - 1][len - 1] = 1;
int start = 1;
while (++ start < len) {
int R = start;
for (int L = 0; R < len; L ++, R ++) {
if (arr[L] == arr[R]) {
dp[L][R] = 2 + dp[L + 1][R - 1];
} else {
dp[L][R] = Math.max(dp[L + 1][R], dp[L][R - 1]);
}
}
}
return dp[0][len - 1];
}