最长上升子序列

一个数的序列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]+" ");
        }
    }
posted @ 2017-02-11 21:38  xxx0624  阅读(343)  评论(0编辑  收藏  举报