最长上升子序列
DP
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
for(int i = 0; i < nums.length; i++){
dp[i] = 1;
}
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int ans = dp[0];
for(int i = 1; i < dp.length; i++){
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
贪心 + 二分
用数据lis保存上升子序列,先把nums[0]放进lis[0]。遍历一遍nums,当前元素如果大于lis最后元素,放进lis最后,并更新上升子序列的长度;否则在lis中找到第一个大于nums[i]的下标,并把lis这一位替换成nums[i],查找的过程用二分实现,左右边界初始值、更新的语句一定要熟练!
class Solution {
public int lengthOfLIS(int[] nums) {
int[] lis = new int[nums.length];
int cnt = 0;
lis[cnt++] = nums[0];
for(int i = 1; i < nums.length; i++){
if(nums[i] > lis[cnt - 1]){
lis[cnt++] = nums[i];
} else{
//搜lis!!!!不是搜原数组!!!
lis[search(lis, 0, cnt - 1, nums[i])] = nums[i];
}
}
return cnt;
}
//找第一个比target大的下标
private int search(int[] a, int left, int right, int target){
while(left <= right){
int mid = left + ((right - left) >> 1);
if(a[mid] < target){
left = mid + 1;
} else{
right = mid - 1;
}
}
return left;
}
}