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;
	}
}
posted @ 2020-12-03 10:40  BOTAK  阅读(61)  评论(0编辑  收藏  举报