最长上升子序列
- 给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例1
输入: [10,9,2,3,7,5,101,6]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
[10,9,2,3,7,5,101,6]
的最长子序列是[2,3,7,101]
[10,9,2,3,7,5,101,6,1]
的最长子序列也是[2,3,7,101]
- 无序数组的最长上升子序列是以
nums[i]
结尾的最长递增子序列的长度
动态规划
- 定义: dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。
- 对于数组
[10,9,2,3,7,5,101,6]
- dp[0] = 1
- dp[1] = 1
- dp[2] = 1
- dp[3] = 2 = dp[2] + 1
- dp[4] = 3 = dp[3] + 1
- dp[5] = 3 = dp[3] + 1
- dp[6] = 4 = dp[4] + 1
- dp[i]=max(dp[j])+1,其中0≤j
dp[0] = 1(base)
# 进行状态转移
for 状态1 in 状态1的所有取值:
dp[i] = base
for 状态2 in 状态2的所有取值:
dp[i] = max(dp[i], dp[j] + 1)
export const lengthOfLIS = nums => {
const len = nums.length
if (!len) return 0
const dp = new Array(len).fill(1)
for (let i = 0; i < len; i++) {
for (let j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1)
}
}
}
return Math.max.apply(null, dp)
}
二分查找
维护一个最小上升dp
- 遇到比dp末尾元素大的push
- 否则,用它覆盖掉dp里比它大的元素中, 最小的那个。
纸牌的堆数就是最长递增子序列的长度
export const lengthOfLIS_binarySearch = nums => {
const len = nums.length
if (len <= 1) return len
const dp = [nums[0]]
let max = 1
for (let i = 1; i < len; i++) {
if (nums[i] > dp[max - 1]) {
dp.push(nums[i])
max++
} else {
let l = 0, r = max - 1
let mid
while (l < r) {
mid = (l + r) >> 1
if (dp[mid] < nums[i]) {
l = mid + 1
} else {
r = mid
}
}
dp[l] = nums[i]
}
}
return max
}
console结果可能不准确,按F12打开控制台查看
← 有效的括号 无重复字符的最长子串 →