zoukankan      html  css  js  c++  java
  • 最长递增子序列问题

    最近学习了这个基础算法原型,最长递增子序列,所谓子序列,就是可以不连续,去除数组中任意元素获得的子数组都是子序列。

    举个栗子,现在有数组arr,长度为5,分别是10,4,5,12,8

    那么这个数组的最长递增子序列长度为3。

    解法一:

    动态规划思想,原问题分成子问题,那么自问题就是到结尾为arr[i]时的最大递增子序列长度。

    创建一个辅助数组dp,和原数组长度相等,这个数组中存放的是以arr[i]结尾的时候,获得的最大递增子序列长度。

    还是上面的栗子,arr数组中的元素为10,4,5,12,8,

    那么dp[0]=1,这个子序列数字10本身

    dp[1]=1,因为4比10小,再来看dp[2],这时候5>4,但是比10小,所以dp[2]=dp[1]+1。

    dp[3],12比4和5都大,所以dp[3]=max(dp[1],dp[2])+1……最终得出dp数组为1,1,2,3,3

    所以得到结果3。这种解法时间复杂度O(n²)

    解法二:

    解法二属于那种打死我我自己也想不出那种,同样的,这种方法也需要一个辅助数组,我们还叫做dp好了。

    但是这次dp存放的不一样了,dp这次存放的是当最长递增子序列为i是,这个序列的最小结尾,注意了,是结尾!

    继续看上面的栗子,10,4,5,12,8,

    dp[0]=10,先把第一个放进去,因为当我们检索到10的时候,最长子序列长度为1,且最小结尾是10,所以存放这个10,

    遍历到4的时候,我们发现,最长长度还是1,但是4比10小,所以4替换掉10,

    继续遍历,5的时候,发现最长长度是2了,ok,那有有效区扩大为2,把5放进去,这时候数组里是4,5,

    12的时候一样,数组变成4,5,12,然后最后一个8比12小,替换掉12,遍历结束,有效区长度为3,所以结果为3

    这个方法的主要思想就是遍历到arr[i]的时候,去找之前的dp数组中第一个比他大的数,有的话替换掉,没有的话,扩大有效区。

    这么一想其实这个方法也是两个循环,但是这个方法比方法一快,原因就在于我们可以加速第二个循环。

    第二层循环我们去找比他大的数,可以用二分啊,所以时间复杂度加速到O(nlogn)。

    下面上代码,

     1 public class GetLis {
     2     // O(n²)
     3     public static int getLis1(int[] arr) {
     4         int maxLen = 1;
     5         int[] dp = new int[arr.length];
     6         for (int i = 0; i < arr.length; i++) {
     7             dp[i] = 1;
     8             for (int j = 0; j < i; j++) {
     9                 if (arr[i] > arr[j] && dp[j] + 1 > dp[i]) {
    10                     dp[i] = dp[j] + 1;
    11                 }
    12             }
    13             maxLen = Math.max(maxLen, dp[i]);
    14         }
    15         return maxLen;
    16     }
    17 
    18     // O(nlogn)
    19     public static int getLis2(int[] arr) {
    20         int maxLen = 1;
    21         int[] dp = new int[arr.length];
    22         int right = 0;
    23         int l = 0;
    24         int r = 0;
    25         int m = 0;
    26         dp[0] = arr[0];
    27         for (int i = 1; i < arr.length; i++) {
    28             l = 0;
    29             r = right;
    30             while (l <= r) {
    31                 m = (l + r) / 2;
    32                 if (arr[i] > dp[m]) {
    33                     l = m + 1;
    34                 } else {
    35                     r = m - 1;
    36                 }
    37             }
    38             right = Math.max(l, right);
    39             dp[l] = arr[i];
    40 
    41         }
    42         maxLen = right + 1;
    43         return maxLen;
    44     }
    45 
    46     public static void main(String[] args) {
    47 
    48         /*
    49          * Scanner scan = new Scanner(System.in); int n = scan.nextInt(); int[]
    50          * arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] =
    51          * scan.nextInt(); } System.out.println(getLis1(arr));
    52          * System.out.println(getLis2(arr)); scan.close();
    53          */
    54 
    55         // 对数器验证一波
    56 
    57         for (int i = 0; i < 100000; i++) {
    58             int n = (int) (Math.random() * 98 + 2);
    59             int[] arr = new int[n];
    60             for (int j = 0; j < n; j++) {
    61                 arr[j] = (int) (Math.random() * 200);
    62             }
    63             int res1 = getLis1(arr);
    64             int res2 = getLis2(arr);
    65             if (res1 != res2) {
    66                 System.out.println("出错了!");
    67             }
    68         }
    69 
    70     }
    71 }
  • 相关阅读:
    HttpClient_4 用法 由HttpClient_3 升级到 HttpClient_4 必看
    环境变量设置错误导致全部命令无法使用解决办法
    正则表达式学习一
    opencv使用中的一点经验记录
    机器学习公开课回顾(一)
    bp算法的一个简单例子
    Ubuntu 16.04安装有道词典
    使用html2canvas库实现一个简单截图功能,还需优化
    PHP-MySQL连接封装-其他简单封装
    PHP获取客户端真实IP
  • 原文地址:https://www.cnblogs.com/huangbw/p/7441573.html
Copyright © 2011-2022 走看看