2.16 求数组中最长的递增子序列
2.16 求数组中最长的递增子序列
基本问题
解法
- 解法1 : 动态规划 时间复杂度为\(O(n^2)\)
- 状态定义 : dp[i] 表示以i结尾的最大上升子序列的长度
- 状态转移方程 : dp[i] = max{dp[j+1],1,0 <= j < i} if(a[j] < a[i])
- 边界处理: dp[i] = 1 , for all i
解法2 : 贪心+二分时间复杂度为\(O(n\log_2n)\)
dp[i]表示表示长度为i+1的LIS结尾元素的最小值。 利用贪心的思想,对于一个上升子序列,显然当前最后一个元素越小,越有利于添加新的元素,这样LIS长度自然更长。 因此,我们只需要维护dp数组,其表示的就是长度为i+1的LIS结尾元素的最小值,保证每一位都是最小值.
举个🌰,[1,-1,2,-3,4,-5,6,-7]
\(dp = [Integer.MIN\_VALUE,0,0,0,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,1,0,0,0,0,0,0,0]\)-> \(dp = [Integer.MIN\_VALUE,-1,0,0,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-1,2,0,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-3,2,0,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-3,2,4,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-5,2,4,0,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-5,2,4,6,0,0,0,0]\)->\(dp = [Integer.MIN\_VALUE,-7,2,4,6,0,0,0,0]\)
All Coding
// 2.16 求数组中最长的递增子序列
import java.util.*;
class Test{
public static void main(String[] args) {
/**
基础问题,写出一个时间复杂度尽可能低的程序,求出一个一维数组中最长的递增子序列的长度
*/
int[] arr = new int[]{1,-1,2,-3,4,-5,6,-7};
System.out.println(dp(arr));
System.out.println(greedyAndBS(arr));
}
/**
状态定义 : dp[i] 表示以i结尾的最大上升子序列的长度
状态转移方程 : dp[i] = max{dp[j+1],1,0 <= j < i} if(a[j] < a[i])
边界处理: dp[i] = 1 , for all i
时间复杂度为O(n**2)
*/
public static int dp(int[] arr){
int len = arr.length;
int[] dp = new int[arr.length];
int res = 1;
Arrays.fill(dp,1);
for(int i = 0;i<len;i++) for(int j =0;j<i;j++) if(arr[j] < arr[i]) dp[i] = Math.max(dp[i],dp[j]+1);
for(int i:dp) res = Math.max(i,res);
return res;
}
/**
dp[i]表示表示长度为i+1的LIS结尾元素的最小值。
利用贪心的思想,对于一个上升子序列,显然当前最后一个元素越小,越有利于添加新的元素,这样LIS长度自然更长。
因此,我们只需要维护dp数组,其表示的就是长度为i+1的LIS结尾元素的最小值,保证每一位都是最小值,
*/
public static int greedyAndBS(int[] arr){
int maxLen = 1;
int len = arr.length;
int[] dp = new int[len+1];
dp[1] = arr[0];
dp[0] = Integer.MIN_VALUE;
for(int i = 1;i<len;i++){
int temp =1;
int start = 0;
int end = maxLen;
if(arr[i] > dp[end]){
maxLen = end+1;
dp[maxLen] = arr[i];
continue;
}
while(start<=end){
int mid = start + (end-start)/2;
if(dp[mid] > arr[i]) end = mid -1;
else if(dp[mid] < arr[i]) start = mid+1;
else break;
}
if(start<=end) continue;
else if(arr[i] > dp[end] && arr[i] < dp[start]){
temp=end+1;
dp[temp] = arr[i];
}
}
return maxLen;
}
}
Saying Less Doing More