• 最长上升子序列


    一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

    思路:dp,即求N个序列的这个状态可以由K(1<=k<=n-1)个序列的状态推导得出

    dp[n]:表示以第n个元素结尾的子序列的最长序列长度

    if a[n]>a[k] dp[n] = max{1,1 + dp[k]}  (1<=k<=n-1)

    解法一:O(n2)

    N2的时间复杂度关键在于每次求第N个元素的时候都遍历一遍前N-1个元素,然后取最大值。

    解法二:O(nlgn)

    nlgn的快速之处在于不是每次去遍历前N-1个元素,而是从一开始就维护一个栈,这个栈中保存的是当前序列的“伪最长子序列”。

    举例:原序列为1,5,8,3,6,7

    栈为1,5,8,此时读到3,用3替换5,得到1,3,8;

    再读6,用6替换8,得到1,3,6;

    再读7,得到最终栈为1,3,6,7。

    最长递增子序列为长度4。

    可以发现栈中的序列不一定是正确的,但是长度肯定是正确的。

    因为维护栈的策略是(假设栈顶元素是top, 新元素是temp)

    if temp > top, temp入栈

    if temp <= top, 首先找出第一个大于等于temp的栈中元素,并用temp替代它。

    public void LIS(int[] nums){
            int[] stack = new int[nums.length];
            int size = 0;
            int[] dp = new int[nums.length];
            for(int i = 0; i < nums.length; i ++){
                if(i == 0){
                    dp[i] = 1;
                    stack[size] = nums[i];
                    size ++;
                }
                else{
                    if(nums[i] > stack[size - 1]){
                        stack[size] = nums[i];
                        size ++;
                        dp[i] = size;
                    }
                    else if(nums[i] == stack[size - 1]){
                        dp[i] = size;
                    }
                    else{
                        int low = 0;
                        int high = size - 1;
                        while(low <= high){
                            int mid = (low + high) / 2;
                            if(stack[mid] == nums[i]){
                                high = mid - 1;
                            }
                            else if(stack[mid] > nums[i]){
                                high = mid - 1;
                            }
                            else{
                                low = mid + 1;
                            }
                        }
                        stack[low] = nums[i];
                        dp[i] = low + 1;
                    }
                }
            }
            for(int i = 0; i < size; i ++){
                System.out.print(stack[i]+" ");
            }
        }
  • 相关阅读:
    Redis 实现队列优先级
    Redis 实现安全队列
    快速理解linux流编辑器sed命令
    Varnish 简介
    手机访问本地服务器
    javascript类的类比详解-大白话版
    优秀前端工程师应该掌握的内容(转自:github)
    mongodb初步使用
    Markdown 语法速查表
    pace.js和NProgress.js两个加载进度插件的一点小总结
  • 原文地址:https://www.cnblogs.com/xxx0624/p/6390041.html
Copyright © 2020-2023  润新知