最长重复子数组[三类动归的第二类 + 典型状态压缩]

前言

动归典型的子问题分解,配合程序的循环和递归,简洁的代码就能完成问题的解答。
动归三类(个人总结),
1-状态不断更新,求得最后一个状态为结果。基础型。
2-状态不断更新,很多个状态,选择其中一个状态,如选最长、最小。中等型。
3-状态不断更新,但不是用的上一个状态,而是前面很多状态中的一个状态。如背包问题。动归本质型,它体现的动归的本质–记忆化数组–目的就是剪枝–空间换时间。
状态压缩三细节,
1-用到的是上一层状态,所以可状态压缩。
2-用到的是上一层且上一个,所以需要反向更新,做到不覆盖。
3-上下层公用一个数组,就必须做到每个值都覆盖,比如continue时一定注意。

一、最长重复子数组

在这里插入图片描述

二、动归

1、动归第二类

//最长重复子数组
public class FindLength {
    /*
    target:求两个数组的公共最长子数组。
    如何求公共子数组?把数组分为子数组,然后给子数组增加一个元素,那么新数组和另一个数组的公共长度就和旧子数组有关,和旧数组以最后一个元素为尾的公共子数组。
    如何得到公共最长?用一个max变量来记录所有公共数组的最长长度。
     */
    public int findLength(int[] nums1, int[] nums2) {
        int max = 0;
        int m = nums1.length, n = nums2.length;
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                //以第j个数字结尾的公共子数组长度。
                dp[i][j] = nums1[i - 1] == nums2[j - 1] ? dp[i - 1][j - 1] != 0 ? 1 + dp[i - 1][j - 1] : 1 : 0;
                if (max < dp[i][j]) max = dp[i][j];
            }
        }
        for (int[] ints : dp) {
            for (int anInt : ints) {
                System.out.print(anInt);
            }
            System.out.println();
        }
        return max;
    }
    /*
    dp三类,
    1-状态不断更新,求得最后一个状态为结果。基础型
    2-状态不断更新,很多个状态,选择其中一个状态,如选最长、最小。中等型。
    3-状态不断更新,但不是用的上一个状态,而是前面很多状态中的一个状态。如背包问题。动归本质型,它体现的动归的本质--记忆化数组--目的就是剪枝--空间换时间。
     */
}

2、状态压缩

//状态压缩
class FindLength2 {
    //动归典型的状态压缩,原因在于它只利用了上一层的状态,不像背包纯纯的记忆化数组。
    public int findLength(int[] nums1, int[] nums2) {
        int max = 0, m = nums1.length, n = nums2.length;

        int[] dp = new int[n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = n; j >= 1; j--) {//用到的不仅是上一层的状态,而且是前一个状态,所以当前状态计算应该倒着覆盖上一层。
                //bug1;使用continue的话,就要先把旧状态赋值为0
                dp[j] = 0;

                if (nums1[i - 1] != nums2[j - 1]) continue;

                dp[j] = 1;
                if (dp[j - 1] != 0) dp[j] += dp[j - 1];

                if (max < dp[j]) max = dp[j];
            }
        }
        return max;
    }

}

总结

1)动归练习
2)状态压缩

参考文献

[1] LeetCode 最长重复子数组

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值