一、题目描述
Given an unsorted array of integers, find the length of longest increasing subsequence.
Input: [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Note:
There may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
二、题解
方法一:dp
能找到思路了!
- 定义状态:dp[i] 表示下标至 i 为止的最长上升子序列。
- 思考状态转移方程:对于每一个元素,都要在区间
检查 LIS 的长度。
- 思考初始化:对于长度大于 0 的子序列,其最短的上升子序列为自身。
- 思考输出:
如果你不理解最优子结构是 ,可以模拟一下这段样例: ,答案是 6.
public int lengthOfLIS(int[] nums) {
final int N = nums.length;
int[] dp = new int[N];
Arrays.fill(dp, 1);
for (int i = 1; i < N; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i])
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
int max = Integer.MAX_VALUE;
for (int i : dp)
if (i > max)
max = i;
return max;
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,
方法二:二分查找优化(没想道)
遍历原数组 nums,将每个元素按照规则二分插入数组 LIS 中,LIS 中的元素都是升序排列的。
- 如果 LIS 中的元素比我大,我就覆盖 LIS 中第一个比我大的元素。
- 可用二分。
- 否则,加到 LIS 的后面。
public int lengthOfLIS1(int[] nums) {
final int N = nums.length;
if (N < 2) return N;
int[] LIS = new int[N];
LIS[0] = nums[0];
int p = 1;
for (int i = 1; i < N; i++) {
if (nums[i] > LIS[p]) {
LIS[++p] = nums[i];
continue;
}
int l = 0, r = p;
while (l < r) {
int mid = l + ((r - l) >>> 1);
if (nums[i] > LIS[mid]) l = mid + 1;
else r = mid;
}
LIS[l] = nums[i];
}
return p;
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,