给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
思路与代码
动态规划
dp[i]
代表以下标i
结尾的最长上升子序列大小(最长子序列必须以nums[i]
结尾)。
时间复杂度 O(n²)
空间复杂度 O(n)
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
int res = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = i - 1; j >= 0; j--) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
res = Math.max(res, dp[i]);
}
return res;
}
}
贪心+二分查找
来自LeetCode 作者 :coldme
很具小巧思。新建数组 tail
,用于保存最长上升子序列。
对原序列进行遍历,将每位元素二分插入 cell 中。
- 如果
tail
中元素都比它小,将它插到最后 - 否则,用它覆盖掉比它大的元素中最小的那个。
时间复杂度 O(n)
空间复杂度 O(n)
class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
int res = 0;
for (int num : nums) {
int i = 0;
int j = res;
while (i < j) {
int m = (j - i) / 2 + i;
if (num <= tails[m]) j = m;
else i = m + 1;
}
tails[j] = num;
if (j == res) res++;
}
return res;
}
}