描述:
给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。
说明
最长上升子序列的定义:最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低到高排列的子序列,这种子序列不一定是连续的或者唯一的。
样例
给出 [5,4,1,2,3],LIS 是 [1,2,3],返回 3
给出 [4,2,4,5,3,7],LIS 是 [2,4,5,7],返回 4
挑战
要求时间复杂度为O(n^2) 或者 O(nlogn)
写这个题的原因就是觉得这个算法好玩,之前没有用过。
1. 一般我们首先想到的是:
- 对
nums
数组进行遍历,如果后一个数比前一个数大,将count++
,如果遇到前一个数大于后一个数,将count
push进counts
进行保存并且将count
重置为0
.- 如此反复,直到结束。最后我们取counts中最大的数即为我们要计算的数。
(当然复杂度很高啊!!!)
代码:
const normal = (nums) => {
if (nums === null || nums.length === 0) {
return 0;
}
let count = 0;
let counts = [];
len = nums.length;
for (let i = 0; i < len; i++) {
for (let j = 1; j < len; j++) {
if (nums[i] < nums[j]) {
count++;
} else {
counts.push(count);
count=0;
}
}
}
return Math.max(...counts);
};
let test = [2, 1, 2, 5, 6, 8, 3, 1];
console.log(normal(test));
然而,在我看别人的思路的时候,发现一个觉得很好玩的算法。
- 首先初始化一个长度为
nums.length
元素全部为1
的数组arr
。- 我们给两个指针
i
和j
,i
从arr[1]
开始,j
从arr[0]
开始对其进行操作,并且保证j<i
.- 因为arr数组和nums数组的下标一一对应,所以我们再对nums元素进行比较的时候,如果出现升序队列,即可对
arr[i]
和arr[j]
的++
进行子序列长度的计算。- 最后取得的arr[i]即为我们要计算的值。
- 整体思路也就是:用初始化为1的数组元素直接进行计数。之前貌似用过,但是也忘了。。。
代码:
const longestIncreasingSubsequence = (nums) => {
if (nums === null || nums.length === 0) {
return 0;
}
let len = nums.length;
//初始化一个元素值全部为1的数组。
let arr = new Array(len).fill(1);
for (let i = 1; i < len; i++) {
for (let j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
arr[i] = Math.max(arr[i], arr[j] + 1)
}
}
}
let longest = -Infinity;
for (let i = 0; i < len; i++) {
console.log(arr[i]);//1,1,2,3,4,5,3,1
longest = Math.max(longest, arr[i])
}
return longest;
};
let test = [2, 1, 2, 5, 6, 8, 3, 1];
console.log(longestIncreasingSubsequence(test));
em…感觉自己懂了,但是貌似没有写清楚,反正也就是很简单的东西,看代码看代码看代码。结束!!!