从暴力递归到动态规划

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
n012345678910
v-11-------?

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 -> 6

dp[j][i] = dp[j - 1][i - 1] + dp[j + 1][i - 1];

cur | rest0123456
0-------
10001040
2001040?(14)
301030100
410206020
501030100
600104014
70001040
/**
 * @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 | R0123
015234(?)234
1-523312
2--233233
3---7

gMap[ ][ ] :
gfMap[ i ][ i ] = 0;
gMap[ L ] [ R ] = Math.min(fMap[ L ][ R - 1 ], fMap[ L + 1 ][ R ]);

L | R0123
0015(?) 12
1-05233
2--07
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 | rest0123
0059(?)11
105911
20577
30222
40000
/**
 * @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”

index01234567
cnt(?)32110111
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 | R0123456
01223556
1-113346
2--11444
3---1223
4----113
5-----11
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];
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值