已知一个序列{a1,a2,…,an},若存在i、j,满足i<j && ai<aj,则将{ai,aj}成为一个递增子序列。而最长上升子序列问题就是要在一个序列中找到一个长度最长的递增子序列。
以 [10,9,2,5,3,7,101,18] 为例:
- 遍历这个数组
- 对于当前索引为i的值,在索引小于i的部分找到一个j,满足dp[j] = max{dp[k]| 0 < k < i && a[j] < a[i] }
- dp[i] = dp[j] + 1
- 最后找出dp[0…n-1]的最大值
Solution 1:动态规划 T(n) = O(n²)
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
int ans = 0;
for(int i=0; i<n; i++){
dp[i] = 1; //初始化,自己单独为一个上升子序列
for(int j=0; j<i; j++){
if(nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
Solution 2:动态规划 + 二分查找 T(n) = O(nlogn)
class Solution {
public int lengthOfLIS(int[] nums) {
int size = 0, n = nums.length;
int[] tail = new int[n];
for(int i=0; i<nums.length; i++) {
int location = binarySearch(tail, 0, size, nums[i]);
tail[location] = nums[i];
if(location == size) size++;
}
return size;
}
}
public int binarySearch(int[] tail, int l, int r, int key) {
while(l < r){
int mid = l + (r - l) / 2;
if(tail[mid] == key) return mid;
else if(tail[mid] > key) r = mid;
else l = mid + 1;
}
return l;
}
}