1 不连续的子序列
300. 最长递增子序列
注意和 674. 最长连续递增序列 的区别
原理
- dp[i]数组含义表示以nums[i]结尾的最长递增子序列长度
- 递推公式
dp[i] = Math.max(dp[j] + 1, dp[i]) - 注意本题是不连续,所以需要每遍历一个数时,都要从头到当前数搜索一遍,以此来得到dp[i]
JS实现
/**
* @param {number[]} nums
* @return {number}
*/
var lengthOfLIS = function (nums) {
// dp[i]数组含义表示以nums[i]结尾的最长递增子序列长度,dp[0]=1
let dp = Array(nums.length).fill(1)
// 最长递增子序列长度
let res = 1
for (let i = 1; i < nums.length; i++) {
// 每遍历一个数时,都要从头到当前数搜索一遍,以此来得到dp[i]
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[j] + 1, dp[i])
}
}
res = Math.max(res, dp[i])
}
return res
}
1143. 最长公共子序列
原理
- dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
- dp数组的第一行和第一列定义为0
- 递推公式
注意这里是不连续的,见代码
JS实现
/**
* @param {string} text1
* @param {string} text2
* @return {number}
*/
var longestCommonSubsequence = function (text1, text2) {
// dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
let dp = Array(text1.length + 1)
.fill()
.map((item) => Array(text2.length + 1).fill(0))
for (let i = 1; i <= text1.length; i++) {
for (let j = 1; j <= text2.length; j++) {
if (text1[i - 1] === text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
}
}
}
return dp[text1.length][text2.length]
}
2 连续的子序列
674. 最长连续递增序列
原理
- dp[i]表示以nums[i]结尾的连续递增子序列的长度
- 注意本题是连续问题,所以递推公式在写的时候,只需要比较前一个数即可
JS实现
/**
* 注意和300题的区别
* @param {number[]} nums
* @return {number}
*/
var findLengthOfLCIS = function (nums) {
// dp[i]表示以nums[i]结尾的连续递增子序列的长度
let dp = Array(nums.length).fill(1)
let res = 1
for (let i = 1; i < nums.length; i++) {
if (nums[i] > nums[i - 1]) {
dp[i] = dp[i - 1] + 1
}
res = Math.max(res, dp[i])
}
return res
}
718. 最长重复子数组
原理
- dp[i][j]表示以nums1[i-1]和nums2[j-1]结尾的两个数组中,公共的 、长度最长的子数组的长度,这样定义可以方便初始化,因为dp的第一行和第一列是没有意义的(取到了-1)
如果dp[i][j]表示以nums1[i]和nums2[j]结尾的两个数组中,公共的 、长度最长的子数组的长度,那么初始化dp第一行,第一列的时候就需要比较计算
- dp数组的第一行和第一列定义为0
- 递推公式
dp[i][j] = dp[i - 1][j - 1] + 1
JS实现
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findLength = function (nums1, nums2) {
// dp[i][j]表示以nums1[i-1]和nums2[j-1]结尾的两个数组中,公共的 、长度最长的子数组的长度
let dp = Array(nums1.length + 1)
.fill()
.map((item) => Array(nums2.length + 1).fill(0))
let res = 0
for (let i = 1; i <= nums1.length; i++) {
for (let j = 1; j <= nums2.length; j++) {
// 这里一定是nums1[i - 1]和nums2[j - 1]作比较,注意dp数组的含义
if (nums1[i - 1] === nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
}
res = Math.max(res, dp[i][j])
}
}
return res
}