Longest Increasing Subsequence

原创 2015年11月20日 11:45:50

Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?

思路: 题目的意思是求数组中递增序列的最大长度,序列是可以不连续的。用f(i)表示第0~i个数中递增序列的最大长度。 对于每一个nums[i]要求f(i) 的话,需要找出0~(i-1) 中所有小于nums[i] 的数nums[j],其中 0 <= j <=(i-1),记录下最大的f(j) ,记为max ,那么f(i)=max+1 ,否则找不到比nums[i]还要小的数,f(i)=1,并在整个遍历数组的过程中记录递增序列的最大长度res。
对于数组nums = [10, 9, 2, 5, 3, 7, 101, 18] ,res表示所要求的最大递增序列的长度。

  1. 初始值 f(0) =1 ,更新res=1
  2. 对于 i =1 , nums[1]=9 , 在1之前没有小于nums [i] 的数 ,所以f(1)=1, res=1
  3. 对于i=2 ,nums[2]=2, 在2之前没有小于nums[i]的数,所以f(2)=1,res=1
  4. 对于i=3 ,nums[3]=5 ,在3之前小于5的数有2 ,max=f(2)=1,所以f(5)=max+1=2, 此时更新res=2
  5. 对于i=4,nums[4]=3 ,在4之前小于3的数有 2,f(3)=f(2)+1=2, 此时res=2
  6. 对于i=5,nums[5]=7,在 5之前小于7的数有2,3,5 ,而f(2)=1, f(3)=2,f(5)=2 , max是f(2)、f(3)和f(5)中最大的一个,max=2,则f(7)=3,此时更新res=3
  7. 对于i=6,nums[i]=101, 在6之前小于101的有f(0),f(1),f(2),f(3),f(4),f(5),它们之中最大的为3,则max=3,所以f(6)=max+1=4,此时更新res=4
  8. 同理,对于i=7 ,有f(7)=4 ,此时res=4

最后最长递增子序列的长度为res=4

算法如下,但是时间复杂度为o(n^2)。

public class Solution {
    public int lengthOfLIS(int[] nums) {
        int res=0;
        int n=nums.length;
        if(n==0) return 0;
        int[] f=new int[n];
        f[0]=1; res=1;
        for(int i=1;i<n;i++)
        {
            int max=Integer.MIN_VALUE;
            for(int j=i-1;j>=0;j--)
              {
                  if(nums[j]<nums[i])
                    max= max > f[j] ? max : f[j];
              }

                f[i]=( max!=Integer.MIN_VALUE ? max+1 : 1);
                res= res > f[i] ? res : f[i] ;
        }

        return res;
    }
}

改进: 想到是查找算法,上述算法所用的是线性查找,比线性查找更加快的是二分查找算法,但是二分查找算法需要每次可以折半,如果可以查找一个有序的序列那就好了。 我们可以用一个数组len来记录对应长度的序列末尾最小的一个数字,这话说起来比较绕口,举个例子
比如len[3] 表示 长度为3的序列中末尾数字中最小的一个数

有如下序列:

3,1,2,6,4,-1,5,8,9
比如在数字5之前,长度为3的递增序列有 1,2,6 和1,2,4 这两个序列的末尾数字分别为6和4,其中4比6小,所以记录长度为3的递增序列的末尾数字为len[3]=4

容易证明当   i <j 的时候有 len[i] < len[j] ,  假设j=i+k , i<j =i+k 
len[i]=m ,len[i+k] =n 如果m>n 那就说明长度为i的序列的最后一个数字大于长度为i+k的最后一个数字,这个不合理的,m在n的后面,到n的时候序列的长度已经可以是i+k了,到m的时候长度肯定不止i+k了,所以len[i]=m是不合理的,所以一定有 i<j ,就有len[i] < len[j]

这样,可以在遍历到 数组之下标为s的时候 ,在len[1]至 len[s]中找到一个比nums[s]还要小的数r,r对应的长度为索引 idx,更新f(s)=idx+1 ,如果len[idx+1]大于nums[s],更新len[idx+1]=nums[s]

public class Solution {
    public int lengthOfLIS(int[] nums) {
        int res=0;
         int n=nums.length;
         if(n==0) return 0;
         int[] f=new int[n];
         f[0]=1;
         int[] len=new int[n+1];
         len[1]=nums[0];
         for(int i=1;i<n;i++)
         {
             //二分查找len中小于nums[i]的数
             int j=i;
             while(j>=1 && len[j]==0)
                 j--;
             int right=j;
             int left=1;
             while(left<=right)
             {
                 int mid=left+(right-left)/2;
                 if(len[mid]>=nums[i])
                 {
                     right=mid-1;
                 }else 
                     left=mid+1;

             }
              if(right<left) 
                  f[i]= right+1;
             if(len[f[i]]!=0)
               len[f[i]]= len[f[i]] < nums[i] ? len[f[i]] : nums[i];
             else len[f[i]]=nums[i]; 
             res=res > f[i] ? res : f[i];

         }
         return res!=0 ? res : 1;
    }
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

DP (7) -- Ones and Zeroes, Longest Increasing Subsequence, Perfect Squares

Ones and Zeroes,Longest Increasing Subsequence,Guess Number Higher or Lower II

最长递增子序列详解(longest increasing subsequence)

对于动态规划问题,往往存在递推解决方法,这个问题也不例外。要求长度为i的序列的Ai{a1,a2,……,ai}最长递增子序列,需要先求出序列Ai-1{a1,a2,……,ai-1}中以各元素(a1,a2,...

[DP]Longest Increasing Subsequence

The longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of...

最长上升子序列LIS(Longest increasing subsequence)

介绍最长上升子序列问题,也就是Longest increasing subsequence缩写为LIS。是指在一个序列中求长度最长的一个上升子序列的问题。问题描述: 给出一个序列a1,a2,a3,...

ACM2017四川省赛 E Longest Increasing Subsequence

题目链接:https://icpc-camp-cdn.b0.upaiyun.com/permanent/problems/sichuan-2017.pdf 题目大意:给出一组数字序列,求每次删掉一...

Middle-题目33:300. Longest Increasing Subsequence

题目原文: Given an unsorted array of integers, find the length of longest increasing subsequence.For ex...

LeetCode Longest Increasing Subsequence

题目: Given an unsorted array of integers, find the length of longest increasing subsequence. ...

leetcode 300. Longest Increasing Subsequence

Given an unsorted array of integers, find the length of longest increasing subsequence. For examp...

Lintcode 389 Longest Increasing Continuous subsequence II

Give you an integer matrix (with row size n, column size m),find the longest increasing continuous s...

Longest Increasing Subsequence 最长递增子序列

最长递增子序列是一道经典的题目。 在例子中,总共有8个数。为了计算在index = 7 的时候,最长的递增序列,我们先考虑index < 7的时候的递增子序列的情况。 我们开一个数组cache,c...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)