一、最长递增子序列
子序列,由数组派生而来,删除数组中的元素而不改变其余元素的顺序
五部曲
- dp数组含义,
dp[i],表示i之前的以nums[i]结尾的最长递增子序列的长度 - 状态转移方程
if(nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1)
}
dp[i]的初始化,对于每个i,起始大小都是1- 确定遍历顺序,
dp[i]是由从0到i-1的各个位置的最长递增子序列推导而来,所以一定是从前往后遍历 - 举例推导
时间复杂度: 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)
};
二、最长连续递增序列
连续子序列,必须保证连续
五部曲
- dp数组含义,
dp[i],表示nums[i]结尾的最长连续递增子序列的长度 - 递推公式,只需要比较相邻元素,相比上一题,一层循环即可
if(nums[i] > nums[i-1]) {
dp[i] = dp[i-1] + 1
}
dp[i]的初始化,对于每个i,起始大小都是1- 从前往后
- 举例推导
时间复杂度: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)
};
三、最长重复子数组
子数组,其实是数组的连续子序列
用二维数组记录两个字符串的所有比较情况
五部曲
- dp数组的含义,
dp[i][j], 以下标i-1的A,和下标j-1的B,最长重复的子数组 - 确定递推公式
if(A[i-1] === B[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1
}
- 初始化,
dp[0][0]是没有意义的,所以dp[0][0] = 0 - 确定遍历顺序,内外层遍历是A或B都行,从前往后
- 举例
时间复杂度: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
};