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; } }