求最长上升子序列(Lis模板)

实现过程

定义已知序列数组为dp[];dp[1…8]=389,207,155,300,299,170,158,65

我们定义一个序列B,然后令 i = 1 to 8 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了

1)首先,把d[1]有序地放到B里,令B[1] = 389,就是说当只有1一个数字389的时候,长度为1的LIS的最小末尾是389。这时Len=1。

2)然后,把d[2]有序地放到B里,d[2]=207<B[1]=389,所以令B[1] = 207,就是说长度为1的LIS的最小末尾是207,d[1]=389已经没用了。这时Len=1

3)接着,d[3] = 155<B[1]=207,所以令B[1]=d[3]=155,就是说长度为1的LIS的最小末尾是155,这时候B[1] = 155,Len=1

4)再来,d[4] = 300>B[1]=155,所以B[1+1]=B[2]=300,长度为2的LIS最小末尾是300,这时候B[1..2] = 155, 300,Len = 2

5)继续,d[5] = 299,d[5]>B[1]&&d[5]<B[2]。这时令B[2]=d[5]=299,用d[5]替换掉B[2],长度为2的LIS的最小末尾是299,B[1…2]=155,299,。Len=2。

6)第6个, d[6] = 170,和上一个一样B[2]=170,长度为2的LIS最小末尾是170,B[1…2]=155,170。Len=2。

7)第7个, d[7] =158,同样B[2]=158,B[1..2]=155,158。Len=2。

8)最后一个, d[8] = 65<B[1],所以令B[1]=65,这时B[1..2]=65,158,Len=2。

于是我们知道了LIS的长度为2。

扫描二维码关注公众号,回复: 5632110 查看本文章

注意B中存放的并不是LIS序列,而是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。

在B中插入数据是有序的,而且是进行替换而不需要挪动——也就是说,我们可以使用二分查找,将每一个数字的插入时间优化到O(logN)~~~~~于是算法的时间复杂度就降低到了O(NlogN)。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size() == 0)
            return 0;
        int len=0;
        int i,t;
        vector<int>b;
        b.push_back(nums[0]);
        for( i=1;i<nums.size();i++)
        {
            if(nums[i]>b[len])
            {
                b.push_back(nums[i]);
                len++;
            }
            else{
                t=lower_bound(b.begin(),b.end(),nums[i])-b.begin();
                b[t]=nums[i];
            }
        }
        return len+1;
    }
};

猜你喜欢

转载自www.cnblogs.com/-xinxin/p/10585565.html