动态规划-最长递增子序列

来源:互联网 发布:淘宝女装店铺策划书 编辑:程序博客网 时间:2024/04/29 18:10

动态规划:动态规划是一种思想。是由暴力递归简化而来的编程思想,在编程中变化很大。我的总结如下:

1.    最长递增子序列

我们想要找到最长递增子序列,关键要遍历数组。

问题:遍历数组,更新当前最长子序列。

关键在于当前最长子序列怎么更新?假设我们有数组arr[n],那么遍历到i位置我们想要得到当前最长子序列。我们以dp[i]表示当前最长子序列的长度。

第一步已经完成。因为我们关心的只有最长子序列这一件事情,dp[i]一维数组完全可以表述清楚。

第二步:那就是dp[i]要怎么计算?

dp[i]表示到arr[i]的最长子序列为多少。那么也就是…..arr[i]组成的最长递增子序列。好勒!那么只用在arr数组中往前找第一个比它小的设为arr[k],直接dp[i]=dp[k]+1;没找到则赋为1.

这样dp[i]的一般计算方法有了,初值dp[0]=1;

这样dp就有了,而我们显然要找到dp数组中最大的。如果要找这个序列的话,比如最大值为dp[i],我们在arr数组向前找比arr[i]小的位置s且dp[s]=dp[i]-1;依此类推即可获得最长子序列。

分析:

这种做法,求dp的时间复杂度为o(n^2)。

介绍另一种方法来求得dp数组。

利用一个help数组,所谓help数组就是维持着一个动态变化的子序列。向help数组中添加arr数组中的元素,每添加一个元素,更新help数组,获得相应位置的dp值。

更新help数组:添加arr元素,找到第一个大于arr的元素,没有的话将元素添加至help数组,dp更新至此的长度大小。有的话,替换这个元素,dp更新为至此的长度大小。

代码参考如下:

public static int[] lis1(int[] arr) {if (arr == null || arr.length == 0) {return null;}int[] dp = getdp1(arr);return generateLIS(arr, dp);}    //第一种获得dp[]数组的方法public static int[] getdp1(int[] arr) {int[] dp = new int[arr.length];for (int i = 0; i < arr.length; i++) {dp[i] = 1;for (int j = 0; j < i; j++) {if (arr[i] > arr[j]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}}return dp;}public static int[] generateLIS(int[] arr, int[] dp) {int len = 0;int index = 0;for (int i = 0; i < dp.length; i++) {   //获得dp的最大值及下标if (dp[i] > len) {len = dp[i];index = i;}}int[] lis = new int[len];lis[--len] = arr[index];for (int i = index; i >= 0; i--) {                //获取最长子序列路径if (arr[i] < arr[index] && dp[i] == dp[index] - 1) {lis[--len] = arr[i];index = i;}}return lis;}public static int[] lis2(int[] arr) {if (arr == null || arr.length == 0) {return null;}int[] dp = getdp2(arr);return generateLIS(arr, dp);}

//第二种方法获取dp

public static int[] getdp2(int[] arr) {int[] dp = new int[arr.length];int[] ends = new int[arr.length];      //ends就是文中提到的help数组ends[0] = arr[0];dp[0] = 1;int right = 0;int l = 0;            //用于二分查找int r = 0;int m = 0;for (int i = 1; i < arr.length; i++) {l = 0;r = right;while (l <= r) {m = (l + r) / 2;if (arr[i] > ends[m]) {l = m + 1;} else {r = m - 1;}}right = Math.max(right, l);ends[l] = arr[i];dp[i] = l + 1;}return dp;}// for testpublic static void printArray(int[] arr) {for (int i = 0; i != arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void main(String[] args) {int[] arr = { 2, 1, 5, 3, 6, 4, 8, 9, 7 };printArray(arr);printArray(lis1(arr));printArray(lis2(arr));}


0 0
原创粉丝点击