`

编程之美-数组中最长递增子序列

 
阅读更多
import java.util.Arrays;
import java.util.Random;

public class LongestAccendingSubSequence {

	/**
	 * 编程之美 数组中最长递增子序列 
	 * 书上的解法容易理解
	 * 另一方法书上没有提到的是,可以将数组排序(由小到大)得到新的数组,
	 * 然后求排序后的数组与原数组的最长公共子序列
	 * 最长公共子序列可用动态规则求解,见http://bylijinnan.iteye.com/blog/1450435
	 * 最后,可以扩展一下:求最长递增子序列的长度的同时,求出这个子序列
	 */
	
	private static final int MAX_NUM = 10;
	private static int[] source = new int[2 * MAX_NUM];	//source存放-10~10这20个元素
	static {
		int len = 2 * MAX_NUM;
		for (int i = 0; i < len; i++) {
			source[i] = i - MAX_NUM;
		}
	}

	public static void main(String[] args) throws Exception {
		// int[] a = { 1, -1, 2, -3, 4, -5, 6, -7 };
		int i = 0;
		while (i++ < 30) {	//测试30次
			int[] a = generateArray(5); // 在source数组里面随机选取5个不同元素
			System.out.println(Arrays.toString(a));
			int length = lisA(a);
			System.out.println(length);
			int length2 = lisB(a);
			System.out.println(length2);
			if (length != length2) {
				throw new Exception("error");
			}
		}
	}
	
	public static int lisA(int[] a) {
		if (a == null || a.length == 0) {
			return -1;
		}
		int result = 0;
		int len = a.length;
		int[] LIS = new int[len];
		for (int i = 0; i < len; i++) {
			LIS[i] = 1;
			for (int j = 0; j <= i; j++) {
				if (a[j] < a[i] && (LIS[j] + 1) > LIS[i]) {
					LIS[i] = LIS[j] + 1;
				}
			}
		}
		for (int i = 0; i < len; i++) { // 找出LIS[i]的最大值
			if (LIS[i] > result) {
				result = LIS[i];
			}
		}
//		System.out.println(Arrays.toString(LIS));
		return result;
	}

	public static int lisB(int[] a) {
		if (a == null || a.length == 0) {
			return -1;
		}

		int len = a.length;
		int[] minLast = new int[len + 1]; // minLast[i]表示长度为i的递增子序列里(长度相等的递增子序列可能有多个),各个子序列最后一个元素的集合里面的最小值
		minLast[1] = a[0];
		minLast[0] = Integer.MIN_VALUE;
		int[] LIS = new int[len];
		for (int i = 0; i < len; i++) {
			LIS[i] = 1;
		}
		int maxLIS = 1; // 递增子序列的最长长度
		for (int i = 1; i < len; i++) {
			int j = 0;
			//从后往前找。另外,对于i<j,总有minLast[i]<minLast[j],因此minLast是个有序的递增数组。可用二分查找加快速度
			//书上说可以改成for (j = LIS[i-1]; j >= 1; j--) 我认为是不对的,因为maxLIS不一定等于LIS[i-1],且对于m<=n,LIS[m]<=LIS[n]不一定成立
			for (j = maxLIS; j >= 1; j--) {	
				if (a[i] > minLast[j]) { 
					LIS[i] = j + 1;
					break;
				} 
			}
			if (LIS[i] > maxLIS) {
				maxLIS = LIS[i];
				minLast[LIS[i]] = a[i];
			} else if (minLast[j] < a[i] && a[i] < minLast[j + 1]) {
				minLast[j + 1] = a[i];
			}
		}
//		System.out.println(Arrays.toString(LIS));
		return maxLIS;
	}
	
	private static int[] generateArray(int length) {
		assert length > 0;
		int[] a = new int[length];
		Random r = new Random();
		int len = source.length;
		int[] copyOfSource = new int[len];
		System.arraycopy(source, 0, copyOfSource, 0, len);
		for (int i = 0; i < length; i++) {
			int k = r.nextInt(len);
			a[i] = copyOfSource[k];
			copyOfSource[k] = copyOfSource[len - 1];
			len--;
		}
		return a;
	}
	
}
分享到:
评论

相关推荐

    最长递增子序列问题

    最长递增子序列...总结来说,最长递增子序列问题是一个经典的动态规划问题,通过维护一个动态规划数组来找出序列中的最长递增子序列。理解并熟练掌握这种问题的解决方法对于提升算法设计和编程能力非常有帮助。

    c语言编程题之数组操作最长连续递增序列.zip

    如果需要找出序列的具体元素,可以额外维护一个存储最长递增子序列的数组或链表,并在遍历时更新。 总的来说,解决“数组操作最长连续递增序列”的问题,需要对C语言的基本语法、数组操作以及动态规划有深入的理解...

    求数组中最长递增子序列的解决方法

    (编程之美P198-202)分析与解法根据题目的要求,求一维数组中的最长递增子序列,也就是找一个标号的序列b[0],b[1],…,b[m](0 &lt;= b[0] &lt; b[1] &lt; … &lt; b[m] &lt; N),使得array[b[0]]&lt;array[b[1]]&lt;...

    PTA丨最长连续递增子序列

    在这个例子中,`dp` 数组用于存储以每个元素结尾的最长递增子序列的长度,而 `max_len` 用于跟踪全局最长递增子序列的长度。时间复杂度为 O(n^2),空间复杂度为 O(n)。 了解了基本的动态规划解决方案后,还可以考虑...

    最长递增子序列java源码

    在本实验中,我们将探讨如何使用Java编程语言解决“最长递增子序列”(Longest Increasing Subsequence, LIS)的问题。这是一个经典的动态规划问题,在计算机科学和算法设计中具有广泛的应用,例如在股票交易策略、...

    求取最长递增子序列(MFC编程)

    最长递增子序列(Longest Increasing Subsequence, LIS)是计算机科学中一个经典的算法问题,主要涉及到了排序、数组处理和优化策略等概念。在这个场景中,我们将关注使用贪心算法和动态规划来解决这个问题,并结合...

    最长递增子序列多种实现(java)

    最长递增子序列(Longest Increasing Subsequence, LIS)是计算机科学中一种经典的动态规划问题,广泛应用于算法竞赛和实际编程场景。在这个Java实现中,我们将深入探讨如何找到一个序列中长度最长的递增子序列。 ...

    中科大算法导论课程实验 最长递增子序列 报告

    在中科大软件学院开设的算法导论课程实验中,要求学生研究和实现最长递增子序列问题。最长递增子序列(Longest Increasing Subsequence,简称LIS)问题是一个经典的计算机科学问题,其目标是在一个无序的整数序列中...

    最长递增子序列LCS的实现C源码

    最长递增子序列(Longest Increasing Subsequence, LCS)是计算机科学中一种经典的动态规划问题,常见于算法和数据结构的学习。在这个问题中,我们给定一个无序整数序列,目标是找到序列中的一个子序列,使得这个子...

    js代码-求最长递增子序列

    在JavaScript编程中,"求最长递增子序列"(Longest Increasing Subsequence,LIS)是一个经典的动态规划问题。该问题旨在找到一个数组中的最长子序列,使得子序列中的元素顺序是递增的,但子序列不必是连续的。这个...

    中科大算法导论课程实验 最长递增子序列 代码

    在本实验中,我们关注的是“最长递增子序列”(Longest Increasing Subsequence, LIS)这一经典问题,它是算法课程中的一个核心课题,尤其在动态规划的应用上有着重要的地位。中科大软件学院的这个实验旨在让学生...

    排序最长递增子序列红黑树

    因为红黑树已经保持了有序性,所以可以在O(n log n)的时间复杂度内找到最长递增子序列,这比直接在未排序的数组中寻找要高效得多。 红黑树的插入操作会自动调整树的结构以满足其性质,而寻找最长递增子序列可以转化...

    最长递增子序列C程序

    3. 记录最大值:遍历结束后,`dp`数组中的最大值即为最长递增子序列的长度。 4. 反向追踪:为了获取实际的子序列,可以从`dp`数组的最大值开始,逆向查找每个元素的前驱,构建递增子序列。 在压缩包中的"FLS"文件...

    求最长非递增子序列长度

    在最长非递增子序列问题中,我们可以定义一个数组dp,其中dp[i]表示以序列中的第i个元素结尾的最长非递增子序列的长度。我们可以通过遍历序列并比较当前元素与之前元素的关系来更新dp数组。 以下是C++实现该算法的...

    算法实验(整数划分、各类排序、最长递增子序列、幻方矩阵)

    本实验涵盖了几个重要的算法概念,包括整数划分、排序算法、最长递增子序列以及幻方矩阵。下面将逐一详细介绍这些知识点。 1. 整数划分: 整数划分是一个数学问题,它涉及将一个正整数n划分为若干个正整数的和,...

    求一个整数序列的最长递增子序列.doc

    最长递增子序列(Longest Increasing Subsequence,简称LIS)是计算机科学中的一个重要问题,特别是在算法设计和分析中。它要求找到一个给定序列中的一个子序列,使得这个子序列是递增的,并且长度最长。 在给定的...

    Rust中最长递增子序列算法_rust_代码_下载

    在 Rust 编程语言中,最长递增子序列(Longest Increasing Subsequence,简称 LIS)是一种常见的算法问题,它的目标是找到一个给定序列中,长度最长的严格递增子序列。这种问题在多种场景下都有应用,比如优化决策...

    最长递增子序列1

    最长递增子序列(LIS)是数组或序列中一个重要的概念,它的目标是找到一个序列的最长子序列,使得这个子序列中的元素是严格递增的。在给定的描述中,我们看到了三种不同的方法来求解LIS问题。 **方法一:动态规划...

Global site tag (gtag.js) - Google Analytics