暴力递归到动态规划最长回文子序列长度问题

package day_18;

/**
 * 给定一个字符串str,返回这个字符串的最长回文子序列长度
 * 比如 : str = “a12b3c43def2ghi1kpm”
 * 最长回文子序列是“1234321”或者“123c321”,返回长度7
 * 注意:子序列可以要求不连续,但是子串一定要求连续
 * @Author huawei
 * @Date 2021/5/18 22:08
 * @Version 1.0
 */
public class Code01_PalindromeSubsequence {

    public static int palindromeSubsequence(String str){
        if(str == null || str.length() == 0){
            return -1;
        }
        return process(str.toCharArray(),0,str.toCharArray().length - 1);
    }
    // 这个递归函数的意思求出array,在L...R范围内的最长回文子序列
    // 其他的都不管
    // 先采用暴力递归的方式
    public static int process(char [] array,int L,int R){
        if(L == R){
            // L....R范围内只有一个数字
            return 1;
        }else if(L == R - 1){
            // L...R范围有两个数字,这个时候要判断array[L] == array[R-1]
            // 如果相等返回2
            return array[L] == array[R] ? 2 : 1;
        }else{
            // 其他情况
            // 1.假设子序列以L不结尾,以R结尾
            int p1 = process(array,L + 1,R);
            // 2.假设子序列以L结尾,以R不结尾
            int p2 = process(array,L , R - 1);
            // 3.假设子序列以L不结尾,以R不结尾
            int p3 = process(array, L + 1 ,R - 1);
            // 4.子序列以L和R结尾,但是这个时候一定要array[L] == array[R]才有这种可能
            int p4 = array[L] == array[R] ? (2 + process(array,L + 1, R - 1)) : 0;
            return Math.max(Math.max(p1,p2),Math.max(p3,p4));
        }

    }

    /**
     * 从暴力递归到动态规划
     * 准备一个二维表
     * 注意:这个动态规划还不最好的,还是可以优化的
     * @param str
     * @return
     */
    public static int dp(String str){
        if(str == null || str.length() ==0){
            return -1;
        }
        char [] array = str.toCharArray();
        int N = array.length;
        int [][] dp = new int[N][N];
        // 这里这样写比较方便
        dp[N - 1][N - 1] = 1;
        // 对角线的值为1
        for(int i = 0 ; i < N - 1 ;i++){
            dp[i][i] = 1;
            dp[i][i + 1] = array[i] == array[i + 1] ? 2 : 1;
        }
        // 应该从N - 3 开始
        for(int L = N - 3 ; L >= 0 ; L--){
            for(int R = L + 2 ; R < N ; R++){
                int p1 = dp[L + 1][R];
                // 2.假设子序列以L结尾,以R不结尾
                int p2 = dp[L][R - 1];
                // 3.假设子序列以L不结尾,以R不结尾
                int p3 = dp[L + 1][R - 1];
                // 4.子序列以L和R结尾,但是这个时候一定要array[L] == array[R]才有这种可能
                int p4 = array[L] == array[R] ? 2 + dp[L + 1][R - 1] : 0;
                dp[L][R] = Math.max(Math.max(p1,p2),Math.max(p3,p4));
            }
        }
        return dp[0][N - 1];
    }
    // 这个是对之前dp做的一个优化,因为一个值是依赖左边下边和左下角最大值,所以这个只依赖左边和下边
    public static int dp1(String str){
        if(str == null || str.length() == 0){
            return -1;
        }
        char[] array = str.toCharArray();
        int N = array.length;
        int [][] dp = new int[N][N];
        dp[N - 1][N - 1] = 1;
        for(int i = 0 ; i < N - 1; i++){
            dp[i][i] = 1;
            dp[i][i+1] = array[i] == array[i+1] ? 2 : 1;
        }
        for(int L = N - 3; L >=0 ; L--){
            for(int R = L + 2 ; R < N ;R++){
                int p1 = Math.max(dp[L][R - 1],dp[L + 1][R]);
                if(array[L] == array[R]){
                    p1 += 2;
                }
                dp[L][R] = p1;
            }
        }
        return dp[0][N - 1];

    }

    public static void main(String[] args) {
        String str = "a12b3c43def2ghi1kpmdsfsdfsd";
        /*System.out.println(palindromeSubsequence(str));*/
        System.out.println(dp(str));
        System.out.println(dp1(str));
//        System.out.println(lpsl1(str));
    }

    public static int lpsl1(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        char[] str = s.toCharArray();
        return f(str, 0, str.length - 1);
    }

    // str[L..R]最长回文子序列长度返回
    public static int f(char[] str, int L, int R) {
        if (L == R) {
            return 1;
        }
        if (L == R - 1) {
            return str[L] == str[R] ? 2 : 1;
        }
        int p1 = f(str, L + 1, R - 1);
        int p2 = f(str, L, R - 1);
        int p3 = f(str, L + 1, R);
        int p4 = str[L] != str[R] ? 0 : (2 + f(str, L + 1, R - 1));
        return Math.max(Math.max(p1, p2), Math.max(p3, p4));
    }
}

你可能感兴趣的:(数据结构和算法)