求出 nums [10,9,2,5,3,7,101,18]的最长递增子序列? ###暴力 1.暴力循环,生成和原数组长度一致的新数组dp,且每个元素为1,dp[i]记录的是nums[i]的最长递增子序列的长度,缺点是:时间复杂度是O(n^2),性能不好,也不能记录子序列。
let lengthOfLIS = (nums)=>{
let dp = new Array(nums.length).fill(1);
for(let i =0;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)
}
贪心+二分
- 贪心+二分算法,新生成一个数组tails(严格的递增序列),该数组用于记录递增的子序列,遍历nums,如果nums[i]大于了tails的最后一项,则往里面添加,如果小于就查找出tails里面最小的大于该值的值,并进行替换,这样就能找出最长子序列,(如果我们想要得到最长递增子序列,那么我们要让序列递增的尽可能慢,也就是每次在递增序列 最后加上的那个数要尽可能的小)
let lengthOfLIS3 = function (nums) {
if (nums.length == 0) return 0
//默认是nums的第一项
const tails = [nums[0]]
for (let i = 1; i < nums.length; i++) {
if (nums[i] > tails[tails.length - 1]) {
tails.push(nums[i])
} else {
//因为tails是严格递增的所以可以使用二分查找的方法
let index = getFirstNums(nums[i])
tails[index] = nums[i]
}
}
console.log(`output->lengthOfLIS3----tails`, tails)
return tails.length
function getFirstNums(target) {
let i = 0,
j = tails.length - 1
while (i < j) {
let mid = (i + j) >> 1
if (tails[mid] >= target) {
j = mid
} else {
i = mid + 1
}
}
return i
}
}
记录正确的顺序
以上虽然个数的正确的,但是顺序是不对的,如[2, 3, 1, 5, 6, 8, 7, 9, 4],最长递增子序列长度是6,记录为[1, 3, 4, 6, 7, 9],显然是不对的,vue中使用了树的前驱节点方法保证正确