300. 最长上升子序列

题目描述

给定一个无序的整数数组,找到其中最长上升(这里是严格上升)子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(nlogn) 吗?

方法1

暴力dp算法,时间复杂度o(n^2)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {

    	int n = nums.size();
    	if(n == 0)
    		return 0;
    	int ret = 0;
        //dp[i]含义:以nums[i]为结尾的最长子序列长度
    	vector<int> dp(n,1);
    	for(int i = 0;i < n;i++)//流式处理
    	{
    		for(int j = 0;j < i;j++)
    		{
    			if(nums[i] > nums[j])
    				dp[i] = max(dp[i],dp[j]+1);
    		}
    		if(dp[i] > ret)
    			ret = dp[i];
    	}
    	return ret;        
    }
};

方法2

上面的方法之所以复杂度为o(n2),是因为当我们处理当前位置时,需要以线性的复杂度去搜索dp中保存的中间信息,要想将复杂度缩小到o(nlogn)
我们需要将对dp进行搜索的复杂度降低到o(logn),为此我们想到了有序数组的折半搜索,这需要我们改变dp的定义,为了达到快速搜索的目的,我们需要将原dp中保存的信息进一步精炼提纯整理转化,dp[i]含义变为:
dp[i]: 当前位置之前所有长度为i+1的递增子序列中, 最小的那个序列尾数.
由定义知dp数组必然是一个递增数组(长度为i+1的递增子序列由一个长度为i的递增子序列+一个大于这个长度为i的子序列的尾数的元素组成)
令ret = dp.size()
对数组进行迭代, 依次判断每个数num将其插入dp数组相应的位置:

  1. num > dp[ret-1], 表示num比所有已知递增序列的尾数都大,
    将num添加入dp数组尾部
  2. dp[i-1] < num < dp[i], 只更新相应的dp[i]
    思考查找的最后一步的情况(分为由两个元素时,进行r = mid(此时mid=l)-1操作,
    跳出搜索,应该插入更新的位置为l;由一个元素时,或者发生r = mid(此时mid=l)-1操作,
    跳出搜索,应该插入更新的位置为l;由一个元素时,或者发生l = mid(此时mid=l)+1操作,
    跳出循环,应该插入更新的位置为更新后的l;综上所述,无论哪种情况跳出搜索,最后应该
    插入更新的位置都是l),决定num的插入位置(是用l还是r)
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {

    	int n = nums.size();
    	if(n == 0)
    		return 0;
    	int ret = 0;
        vector<int> dp;
        for(int i = 0;i < n;i++) 
        {
        	if(ret == 0 || dp[ret-1] < nums[i])
        	{
        		dp.push_back(nums[i]);
        		ret++;
        	}
			else        
			{   
				bool find_success = false;
				int l = 0;
				int h = ret-1;
			    while(l <= h) 
			    {
	                int mid = l+(h-l)/2;
	                if(dp[mid] == nums[i])
	                {
	                	find_success = true;
	                	break;
	                }
	                else if(dp[mid] < nums[i])
	                    l = mid+1;
	                else
	                    h = mid-1;
                }
                if(!find_success)
                	dp[l] = nums[i];
            }
            
        }
        return ret;   
    }

};

posted on 2021-05-05 14:05  朴素贝叶斯  阅读(65)  评论(0编辑  收藏  举报

导航