給定一個無序的整數數組,找到其中最長上升子序列的長度。
示例:
輸入: [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;
}