算法修炼Day52|300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

111 阅读3分钟

LeetCode:300. 最长递增子序列 - 力扣(LeetCode)

1.思路

暴力是没有思路的。动规,线性查找每个索引位置所具有的最大递增子序列数值,每个数值位置的初始值都应该为1。且应该考虑数组长度为1时的情况。或者result初始为1。

2.代码实现
class Solution {
    public int lengthOfLIS(int[] nums) {
        // dp[i] 表示 nums[i] 及之前的数字中的最长子序列为 dp[i] 个
        int[] dp = new int[nums.length];
        Arrays.fill(dp, 1); // 每个数字都是一个长度,则每个位置的子序列的最小长度为1
        int result = 1; // 记录每个数字位置递增子序列的结果值
        for (int i = 1; i < nums.length; i++) { // 遍历每个位置
            for (int j = 0; j < i; j++) { // 遍历该位置之前的数字
                if (nums[i] > nums[j]) { // 统计小于当前元素的数字nums[j]
                    dp[i] = Math.max(dp[j] + 1, dp[i]); // 在 dp[j] 的基础上 +1, 与当前 dp[i] 进行比较,取两者中的较大值。
                }
            }
            result = Math.max(dp[i], result); // 记录最大的递增子序列的值
        }
        return result; // 返回结果值
    }
}
3.复杂度分析

时间复杂度:O(n^2).

空间复杂度:O(n).

LeetCode:674. 最长连续递增序列 - 力扣(LeetCode)

1.思路

方法一:最初理解错题意了,想成数值连续了。其实只是大小序列是递增的即可。每个位置作为起始位置进行遍历,循环判断获取符合条件的递增子序列的个数,内层for循环结束之后更新最大递增子序列的个数。

方法二:dp[i]表示以i为开始的最大连续子序列的长度。

2.代码实现
// 暴力解法
class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int maxLen = 0;
        for (int i = 0; i < nums.length; i++) {
            int len = 1;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] > nums[j - 1]) {
                    len++;
                } else {
                    break;
                }
            }
            maxLen = Math.max(maxLen, len);
        }
        return maxLen;
    }
}

// dp[i]以i为开始的最大连续子序列长度
class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int[] dp = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
        }
        // 结果值
        int result = 1;
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i + 1] > nums[i]) {
                dp[i + 1] = dp[i] + 1;
            } 
            result = result > dp[i + 1] ? result : dp[i + 1];
        }
        return result;
    }
}

// dp[i]以i为末尾位置的最大连续子序列长度
class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int[] dp = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
        }
        // 结果值
        int result = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > nums[i - 1]) {
                dp[i] = dp[i - 1] + 1;
            } 
            result = result > dp[i] ? result : dp[i];
        }
        return result;
    }
}
3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(n).

LeetCode:718. 最长重复子数组 - 力扣(LeetCode)

1.思路

dp[i][j]表示i-1,j-1为结尾的两数组的公共子数组的长度。

2.代码实现
// 暴力
class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int maxLen = 0;
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int len = 0; // 当前位置算起的相同子数组的长度
                int p = i; // 目的是避免对 i,j 的起始位置有干扰
                int q = j;
                while (p < nums1.length && q < nums2.length && nums1[p] == nums2[q]) {
                    len++;
                    p++;
                    q++;
                }
                maxLen = Math.max(maxLen, len);
            }
        }
        return maxLen;
    }
}

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int[][] dp = new int[nums1.length + 1][nums2.length + 1];
        int result = 0;
        for (int i = 1; i <= nums1.length; i++) {
            for (int j = 1; j <= nums2.length; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                result = Math.max(result, dp[i][j]);
            }
        }
        return result;
    }
}
3.复杂度分析

时间复杂度:O(n * m).

空间复杂度:O(n).