代码题(25)— 最大子序和最长上升子序列

Posted eilearn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码题(25)— 最大子序和最长上升子序列相关的知识,希望对你有一定的参考价值。

1、53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.empty())
            return 0;
        int res = nums[0];
        int sum = nums[0];
        for(int i=1;i<nums.size();++i)
        {
            if(sum>0)
                sum += nums[i];
            else
                sum = nums[i];
            res = max(res, sum);    
        }
        return res;
    }
};

2、300. 最长上升子序列

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

示例:

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

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

  方法一:时间复杂度为O(n2)

  首先来看一种动态规划Dynamic Programming的解法,这种解法的时间复杂度为O(n2),类似brute force的解法,我们维护一个一维dp数组,其中dp[i]表示以nums[i]为结尾的最长递增子串的长度,对于每一个nums[i],我们从第一个数再搜索到i,如果发现某个数小于nums[i],我们更新dp[i],更新方法为dp[i] = max(dp[i], dp[j] + 1),即比较当前dp[i]的值和那个小于num[i]的数的dp值加1的大小,我们就这样不断的更新dp数组,到最后dp数组中最大的值就是我们要返回的LIS的长度.

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.empty())
            return 0;
        int n = nums.size();
        int res=0;
        vector<int> dp(n,1);
        for(int i=0;i<n;++i)
        {
            for(int j=0;j<i;++j)
            {
                if(nums[j]<nums[i])
                    dp[i]=max(dp[i],dp[j]+1);
            }
            res = max(res, dp[i]);
        }
        return res;
    }
};

   方法二:时间复杂度为O(nlogn)

   思路是先建立一个空的dp数组,然后开始遍历原数组,对于每一个遍历到的数字,我们用二分查找法在dp数组找第一个不小于它的数字,如果这个数字不存在,那么直接在dp数组后面加上遍历到的数字,如果存在,则将这个数字更新为当前遍历到的数字,最后返回dp数字的长度即可,注意的是,跟上面的方法一样,特别注意的是dp数组的值可能不是一个真实的LIS。

 

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.empty())
            return 0;
        vector<int> dp;
        for(int i=0;i<nums.size();++i)
        {
            int low=0,high=dp.size();
            while(low<high)
            {
                int mid = (low+high)/2;
                if(dp[mid]<nums[i])
                    low = mid+1;
                else
                    high=mid;
            }
            if(high>=dp.size())
                dp.push_back(nums[i]);
            else
                dp[high] = nums[i];
        }
        return dp.size();
    }
};

 

以上是关于代码题(25)— 最大子序和最长上升子序列的主要内容,如果未能解决你的问题,请参考以下文章

动态规划法

代码随想录day 31 455.分发饼干 | 376. 摆动序列 | 53. 最大子序和

代码题— 数组最大子序列

精选力扣500题 第29题 LeetCode 53. 最大子序和c++ / java 详细题解

最长上升子序列的长度&最长上升子序列的个数

LeetCode300-最长上升子序列