Longest Increasing Subsequence的两种解法

问题描述:

  给出一个未排序队列nums,如[10, 9, 2, 5, 3, 7, 101, 18]。找出其中最长的增长序列,但不是连续增长序列,如[2, 3, 7, 101]就是对应的最长增长序列LIS,因为序列不唯一,所以要求返回的是长度,如4.

一.动态规划 O(n^2):

  比较容易想到的就是复杂度为O(n^2)的算法。这是一个备忘录算法,也是动态规划算法。需要建立一个备忘录dp,备忘录dp[i]记录序列从下标0到下标i最长的子序列长度。对于dp[j]的值则需要在nums序列红中找到0到(j-1)所有比nums[j]小元素,并在这些元素中选择备忘录dp值最大的一个如dp[k],则dp[j]=dp[k]+1;

public int lengthOfLIS(int[] nums) {
        if(nums==null || nums.length==0)
            return 0;
        int[] bigLength=new int[nums.length];
        for(int i=0;i<nums.length;i++) bigLength[i]=1;
        int maxLength=1;
        for(int i=1;i<nums.length;i++){
       //从前面找到比 nums[i]小,且dp值最大的那个。加1便是当前的值
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i])
                    bigLength[i]=Math.max(bigLength[j]+1,bigLength[i]);
            }
            
            maxLength=Math.max(bigLength[i],maxLength);
        }
        return maxLength;
    }

 

二 .二分法查找O(nlg(n))

  首先建立一个栈stack来存储遍历到当前时刻 i 的一个最长递增序列(栈内是递增序列,但概念和题目中的递增序列不同)。设当前时刻为 i 则

1.如果元素 i 比栈顶元素大则入栈,stack[top++]=nums[i+1];

2.如果元素 i 比栈顶元素小,则在栈中采用二分查找法找到一个位置j 替换成当前元素nums[i] 。 该做法的目的是如果出现小元素就往栈内部替换,当前替换的结果影响下一次的替换,特别是栈顶元素。栈顶元素的替换需要比较stack[top],stack[top--]及nums[i]三个的值。

3.最后输出 栈的长度。

public int lengthOfLIS(int[] nums) {
        if(nums==null || nums.length==0)
            return 0;
            
        int[] stack= new int[nums.length];
        int top=0;
        
        for(int num:nums){
            if(top==0 || stack[top-1]<num) stack[top++]=num;
            else{
              //如果在栈中没有对应的元素,则将找到的插入坐标为 j 返回-j-1. 如果找到则返回对应的坐标位置。
                int i=Arrays.binarySearch(dp,0,top,num);
                i= i<0? -i-1:i;
                dp[i]=num;
            }
        }
        return top;
    }                    

 

   另外网上有关于只用栈没用利用二分法查找法的做法,使得复杂度变为O(n),试了下是不行的。他大概的思路是:

1.如果当前栈为空或栈顶元素小于当前元素nums[i],则入栈

2.如果nums[i]<stack[top] 且 nums[i]>stack[top-1] 则替换栈顶元素,stack[top]=nums[i]。

这种做法忽略了stack[top-1]之前的元素对stack[top-1]的影响。算法代码如下:

public int lengthOfLIS(int[] nums) {
    int len=nums.length;
    Stack<Integer> stack=new Stack<Integer>();
    for(int i=len-1; i>=0; i--)
    {
        if(stack.isEmpty())
        {
            stack.push(nums[i]);
        }else
        {
           int val= stack.pop();
           if(stack.isEmpty())
           {
               if(nums[i]>=val)
               {
                   val=nums[i];
               }else
               {
                   stack.push(val);
                   val=nums[i];
               }
           }else
           {
               int up=stack.peek();
               if(nums[i]<val)
               {
                   stack.push(val);
                   val=nums[i];
               }else if(nums[i]>val && nums[i]<up)
               {
                   val=nums[i];
               }
           }
           stack.push(val);
        }
    }
    return stack.size();
}
View Code
posted @ 2015-11-04 17:11  along-JL  阅读(389)  评论(0编辑  收藏  举报