力扣解题思路:最长回文子序列/最长回文子串/数组拷贝问题 纠错记录

516. 最长回文子序列

思路:在这里插入图片描述
这一题思路比较巧妙,记录一下。设dp[i][j]表示s[i:j]中的最长回文子序列长度,则

(1) s[i] == s[j] ==> dp[i][j] = dp[i+1][j-1] + 2;

(2) s[i] != s[j] ==> dp[i][j] = max(dp[i+1][j], dp[i][j-1])

初始化: dp[i][i] = 1

由i,j的更新方式知道i应该逆序,j应该正序,且j应该比i大:

for (int i = n - 1; i >= 0; i--) {
    dp[i][i] = 1;
    for (int j = i + 1; j < n; j++) {
		//更新
    }
}

更新方式:

        if (s.charAt(i) == s.charAt(j)) {
            dp[i][j] = dp[i + 1][j - 1] + 2;
        } else {
            dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
        }

完整代码如下:

public int longestPalindromeSubseq(String s) {
    if (s == null || s.length() == 0) return 0;
    int n = s.length();
    int[][] dp = new int[n][n];
    for (int i = n - 1; i >= 0; i--) {
        dp[i][i] = 1;
        for (int j = i + 1; j < n; j++) {//i+1不会越界,因为j = i + 1; j < n
            if (s.charAt(i) == s.charAt(j)) {
                dp[i][j] = dp[i + 1][j - 1] + 2;
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[0][n - 1];
}

当然还可以进行空间优化,但是就需要另外一个数组保存上一轮的结果,最开始我是这样写的:

public int longestPalindromeSubseq(String s) {
    if (s == null || s.length() == 0) return 0;
    int n = s.length();
    int[] pre = new int[n];
    int[] cur = new int[n];
    for (int i = n - 1; i >= 0; i--) {
        cur[i] = 1;
        for (int j = i + 1; j < n; j++) {
            if (s.charAt(i) == s.charAt(j)) {
                cur[j] = pre[j - 1] + 2;
            } else {
                cur[j] = Math.max(pre[j], cur[j - 1]);
            }
        }
        for(int p=0;p<n;p++) pre[p] = cur[p];
        //pre = cur;
        cur = new int[n];
    }
    return pre[n - 1];
}

因为pre这个数组保存上一层遍历结果,所以内循环结束就得更新一次,即把cur赋值给pre,注意这里必须是复制整个数组,而不是只传递引用,所以我这样写

for(int p=0;p<n;p++) pre[p] = cur[p];

然后再清空cur数组

cur = new int[n];

这样写运行完全正确,因为我知道如果直接传递pre = cur则修改pre的同时cur也会被修改!于是我想证明我是错的,于是我就写成这样

//for(int p=0;p<n;p++) pre[p] = cur[p];
        pre = cur;
        cur = new int[n];

然后又跑了一遍,发现也是对的!!!为什么呢???难道数组的等号赋值传递的不是引用吗?当然是!但是这里问题不在这里,我举个例子:

		int[] array = new int[5];
		int[] temp = new int[5];
		array[0] = 1;
		temp[0] = 2;
		temp = array;
		System.out.println(temp[0]);
		array[0] = 3;
		//array = new int[5];
		System.out.println(temp[0]);

这段代码的输出是1,3,很显然是因为传递引用后array被修改所以temp也被修改,接下来看下一段:

		int[] array = new int[5];
		int[] temp = new int[5];
		array[0] = 1;
		temp[0] = 2;
		temp = array;
		System.out.println(temp[0]);
		//array[0] = 3;
		array = new int[5];
		System.out.println(temp[0]);

这里输出是1,0吗?不是!!!是1,1,为什么呢,问题就在于array = new int[5];也就是array重新指向了另一个数组,然而之前存在于内存中的数组【1,0,0,0,0】还是存在的,被temp指向,这时两个数组各自修改都不会影响对方(而之前两个引用指向统一内存位置)!!!!

5. 最长回文子串

思路:
在这里插入图片描述
这一题和上一题类似,但是字符串必须是连续的,所以dp数组就不可以存长度了,应该改为布尔数组:

    public String longestPalindrome(String s) {
        boolean[][] dp = new boolean[s.length()][s.length()];
        for(int i=0;i<s.length();i++) dp[i][i] = true;
        int max = 0;
        int start = 0;
        int end = 0;
        for(int i=s.length()-1;i>=0;i--){
            for(int j=i+1;j<s.length();j++){
                if(s.charAt(i) == s.charAt(j)){
                    if(j - i < 3){//这里需要注意
                        dp[i][j] = true;
                    }else{
                        dp[i][j] = dp[i+1][j-1];
                    }
                }else{
                    dp[i][j] = false;
                }
                if(dp[i][j] && j - i + 1 > max){
                    start = i;
                    end = j;
                    max = j - i + 1;
                }
            }
        }
        return s.substring(start,end+1);
    }

也可以进行空间优化,后续再补充。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值