leetcode题:300. 最长上升子序列(中等)

一、题目描述:300. 最长上升子序列(中等)

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、解题思路

方法一、动态规划

1、定义动态数组dp,dp[j]记录当前i点最大上升子序列个数,初始化为0,动态方程从对0到i中间的点j,当nums[i]>nums[j] ,dp[i] = max(dp[j] + 1,dp[i])。dp数组中最大值就是最大上升子序列值。复杂度为O(n)

方法二、动态规划+二分查找

定义动态数组dp,dp存放当前最大上升子序列(这边并不是真正的上升子序列)。

leetcode上的描述

很具小巧思。新建数组 cell,用于保存最长上升子序列。

对原序列进行遍历,将每位元素二分插入 cell 中。

如果 cell 中元素都比它小,将它插到最后
否则,用它覆盖掉比它大的元素中最小的那个。
总之,思想就是让 cell 中存储比较小的元素。这样,cell 未必是真实的最长上升子序列,但长度是对的。

三、代码

方法二、

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size() == 0)
            return 0;
       vector<int> dp;
        dp.push_back(nums[0]);
        for(int i = 0; i < nums.size(); i++)
        {
            //print(dp);
            int num = nums[i];
            int index = findNum(dp,num);
            //cout<<"num="<<num<<endl;
            //cout<<"index="<<index<<endl;
            if(index < 0)
            {
                dp[0] = num;
            }
            else if(index >= dp.size())
            {
                dp.push_back(num);
            }
            else
            {
                if(dp[index] > num)
                {
                    dp[index] = num;
                }
                else if (dp[index] < num)
                {
                    if(index + 1 < dp.size())
                    {
                        //cout<<index+1<<endl;
                        if(dp[index+1] > num)
                        dp[index+1] = num;
                    }
                    else
                    {
                        dp.push_back(num);
                    }
                }
            }
        }
        return dp.size();
    }
    void print(vector<int> & dp)
    {
        for (int i = 0; i < dp.size(); i++)
        {
            cout<<dp[i]<<",";
        }
        cout<<endl;
    }
    int findNum(vector<int>& dp,int & num)
    {
        int left = 0;
        int right = dp.size() -1 ;
        int mid = (left + right)/2;
        while(left <= right)
        {
            
            if(dp[mid] == num)
                return mid;
            if(dp[mid] < num)
            {
                left = mid+1;
            }
            else
            {
                right = mid-1;
            }
            mid = (left + right)/2;
        }
        return mid;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值