给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
定义dp[i]为截止数组的第i个位置的最长上升序列,定义转移方程:
for(int i = 0;i < len-1;i++) {
for(int j = i+1;j < len;j++){
if(nums[i] < nums[j]){
dp[j] = Math.max(dp[i]+1,dp[j]);
}
}
}
public static int lengthOfLIS(int[] nums) {
int len = nums.length;
if(len ==0){
return 0;
}
int dp[] = new int[len+1];
for(int i = 0;i < len;i++) {
dp[i] = 1;
}
for(int i = 0;i < len-1;i++) {
for(int j = i+1;j < len;j++){
if(nums[i] < nums[j]){
dp[j] = Math.max(dp[i]+1,dp[j]);
}
}
}
int max = 0;
for(int i = 0;i < len;i++){
max = Math.max(max,dp[i]);
}
System.out.println();
return max;
}
优化
上述算法是O(N^2)的,使用二分查找可以将时间复杂度优化为O(nlogn)
定义dp[]存放组成最长数组的序列,如果dp[cnt] < arr[i]则dp[++cnt] = arr[i] 否则将dp[]数组中大于且接近arr[i]的一个数找出来 ,替换成arr[i]。
public static int lengthOfLIS(int[] nums){
int len = nums.length;
if(len <=1){
return len;
}
int[] dp = new int[len+1];
dp[0] = nums[0];
int cnt = 0;
for(int i = 1;i < len;i++){
if(dp[cnt] < nums[i]){
dp[++cnt] = nums[i];
} else {
dp[upSearch(dp,cnt,nums[i])] = nums[i];
}
}
return cnt+1;
}
private static int upSearch(int[] dp, int len, int x) {
int mid,l=0;
while(l<=len)
{
mid = (l+len)>>1;
if(dp[mid] == x){
return mid;
}
if(dp[mid]<x)
l = mid+1;
else
len = mid-1;
}
return l;
}