0
点赞
收藏
分享

微信扫一扫

最长递增子序列 (LIS)动态规划,贪心+二分 (java版)

吴wuwu 2022-02-08 阅读 50

目录

问题描述:

动态规划:(n^2)

java代码:

贪心+二分:(nlongn)

java代码:

binnarySearch()的使用:


问题描述:

给定一个序列,如:arr=[10, 9, 2, 5, 3, 7, 101, 18],求该序列的最长递增子序列。

最长递增子序列:longest increasing subsequence(LIS),可以用n^2复杂度的动态规划求解,也可以用nlongn复杂度的贪心加二分求解。

动态规划:(n^2)

设dp[i]表示为arr[i]结尾的最大长度,则开始时dp数组中元素值都为1(自身长度),以上述数组为例:

java代码:

public class Main {
	public static void main(String[] args) {
		int []arr = new int[] {10, 9, 2, 5, 3, 7, 101, 18};
		int []dp = new int[arr.length];
		
		for(int i = 0; i < arr.length; i++) {//遍历arr中元素
			dp[i] = 1;//dp数组初始化为1,即本身长度为1
			for(int j = 0; j < i; j++) {//遍历dp[i]之前元素
				if(arr[j] < arr[i]) {//小于当前元素
					dp[i] = Math.max(dp[i], dp[j] + 1);//比较
				}
			}
		}
		int max = Integer.MIN_VALUE;//找dp中所存放的最大值
		for(int i = 0; i < arr.length; i++) {
			max = Math.max(max, dp[i]);
		}
		System.out.println(max);
	}
}

贪心+二分:(nlongn)

对于一个上升的子序列,结尾值的元素越小,越有利于后续在其后添加新的元素,使得长度最长。

以arr=[10, 9, 2, 5, 3, 7, 101, 18]为例,设dp数组中元素值为最长的序列,以下是dp的动态变化过程:

java代码:

import java.util.Arrays;

public class Main {
	public static void main(String[] args) {
		int []arr = new int[] {10, 9, 2, 5, 3, 7, 101, 18};
		int []dp = new int[arr.length];
		
		int len = 0;//二分查找的最右端(卡范围),dp中“有意义”的元素个数
		for(int i = 0; i < arr.length; i++) {
			int index = Arrays.binarySearch(dp, 0, len, arr[i]);
			if(index < 0) {
				index = -(index + 1);//将index改为期待位置
			}
			dp[index] = arr[i];//更新或追加
			if(index == len) {
				len++;
			}
		}
		System.out.println(len);
	}
}

binnarySearch()的使用:

在二分查找时调用了工具类Arrays的binnarySearch(),在使用该方法查找时,找到待查找的元素,则返回找到的索引;如果找不到,则返回一个负数,假设排好序时,不存在的元素应该位于索引r处,则 -(r + 1) 便是返回的负数值。

例如:

public class BinarySeach {
	public static void main(String[] args) {
		int[] src = { 1, 2, 4, 5, 7, 8, 12 };
		System.out.print(Arrays.binarySearch(src, 10)); //-7
	}
}

10在src数组中不存在,则返回一个负数,将10放入有序数组src时应该位于索引6处,所以返回的负数值为 -(6 + 1) ,即返回-7。

举报

相关推荐

0 条评论