算法练习day45

121 阅读3分钟

一、最长递增子序列

子序列,由数组派生而来,删除数组中的元素而不改变其余元素的顺序

五部曲

  1. dp数组含义,dp[i],表示i之前的以nums[i]结尾的最长递增子序列的长度
  2. 状态转移方程
if(nums[i] > nums[j]) {
    dp[i] = Math.max(dp[i], dp[j] + 1)
}
  1. dp[i]的初始化,对于每个i,起始大小都是1
  2. 确定遍历顺序,dp[i]是由从0到i-1的各个位置的最长递增子序列推导而来,所以一定是从前往后遍历
  3. 举例推导

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

/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function(nums) {
    let dp = new Array(nums.length).fill(1)
    for(let i = 1; i < nums.length;i++) {
        for(let j = 0; j < i; j++) {
            if(nums[i] > nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1)
            }
        }
    }
    return Math.max(...dp)
};

二、最长连续递增序列

连续子序列,必须保证连续

五部曲

  1. dp数组含义,dp[i],表示nums[i]结尾的最长连续递增子序列的长度
  2. 递推公式,只需要比较相邻元素,相比上一题,一层循环即可
if(nums[i] > nums[i-1]) {
    dp[i] = dp[i-1] + 1
}
  1. dp[i]的初始化,对于每个i,起始大小都是1
  2. 从前往后
  3. 举例推导

时间复杂度:O(n) 空间复杂度:O(1)

/**
 * @param {number[]} nums
 * @return {number}
 */
var findLengthOfLCIS = function(nums) {
    let dp = new Array(nums.length).fill(1)
    for(let i = 1; i < nums.length;i++) {
        if(nums[i] > nums[i-1]) {
            dp[i] = dp[i-1] + 1
        }
    }
    return Math.max(...dp)
};

三、最长重复子数组

子数组,其实是数组的连续子序列

用二维数组记录两个字符串的所有比较情况

五部曲

  1. dp数组的含义,dp[i][j], 以下标i-1的A,和下标j-1的B,最长重复的子数组
  2. 确定递推公式
if(A[i-1] === B[j-1]) {
    dp[i][j] = dp[i-1][j-1] + 1
}
  1. 初始化,dp[0][0]是没有意义的,所以dp[0][0] = 0
  2. 确定遍历顺序,内外层遍历是A或B都行,从前往后
  3. 举例

时间复杂度:O(n × m),n 为A长度,m为B长度 空间复杂度:O(n × m)

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findLength = function (nums1, nums2) {
    let dp = new Array(nums1.length + 1).fill(0).map(_ => new Array(nums2.length + 1).fill(0))
    let result = 0
    for (let i = 1; i <= nums1.length; i++) {
        for (let j = 1; j <= nums2.length; j++) {
            // dp里的i对应的是数组中第i-1的索引
            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
};

滚动数组

dp[i][j]都是由dp[i-1][j-1]推导而来,压缩为一维数组,dp[j]都是由dp[j-1]推导

相当于把上一层的dp[i-1][j]拷贝到下一层dp[i][j]来用

时间复杂度:O(n × m),n 为A长度,m为B长度 空间复杂度:O(m)

var findLength = function (nums1, nums2) {
    let dp = new Array(nums2.length + 1).fill(0)
    let result = 0
    for (let i = 1; i <= nums1.length; i++) {
        for (let j = nums2.length; j > 0; j--) {
            if (nums1[i - 1] === nums2[j - 1]) {
                dp[j] = dp[j - 1] + 1
            } else {
                dp[j] = 0
            }
            result = Math.max(result, dp[j])
        }
    }
    return result
};