leetcode剑指 Offer 42. 连续子数组的最大和&120. 三角形最小路径和&300. 最长上升子序列

剑指 Offer 42. 连续子数组的最大和&120. 三角形最小路径和&300. 最长上升子序列

题目

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

提示:

1 <= arr.length <= 10^5
-100 <= arr[i] <= 100

注意:本题与主站 53 题相同:https://leetcode-cn.com/problems/maximum-subarray/

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof

分析

这道题目是要使用O(n)的算法,一开始我想到的就是O(n2)的算法,很明显不符合题目要求,又因为这道题目是动态规划(这里其实偷懒了),所以我们的dp的状态定义就在一维上面,这样dp[i]肯定就是0~i的连续最大和了,重要的就是如何状态转移.
我们需要的就是对前面的和当前元素的连接记前面的元素提供的大小为last,如果前面的小于0,那么我前面的还不如不要,last直接变成自己,给下一个元素用,如果是正数,那么正好给我加上,作为下一个元素的last.

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ans=0,sz=nums.size(),last=0;
        for(int i=0;i<sz;i++)
        {
            last+=nums[i];
            if(last<0) last=0;
            last=max(last,nums[i]);
            ans=max(ans,last);
        }
        return  ans;
    }
};

这样写出来过了188个逻辑应该是没问题的,有一个问题,本来我认为可以不选,所以最小是0,但是其实是要选一个
[-1] 这样的答案是-1
所以就需要一定的改动
先计算last作为一种答案,并进行答案的求取,这样就可以取到赋值,之后再进行last小于0的舍弃,完美.

代码

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ans=-9999,sz=nums.size(),last=0;
        for(int i=0;i<sz;i++)
        {
            last+=nums[i];
            last=max(last,nums[i]);
            //
            //if(last<0) last=nums[i];
            //else last=last+nums[i];
            //和上面两句可以互换
            ans=max(ans,last);
            last=max(0,last);
        }
        return  ans;
    }
};

题目

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

说明:

如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle

分析

这道题经典的动态规划,子结构很明显,就是小的三角形,考虑细节的状态转移
对于
[
[1],
[2,3],
]
对于1来说,向下只有两种选择,2和3,那么肯定要选最小的2,那么从底部到达1的最小的路径就是3=1+2.
所以这时就基本清楚了,只要考虑好索引之间的关系就可以完成不断向上的动态规划,返回答案dp[0][0]就可以了

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int sz=triangle.size();
        for(int i=sz-2;i>=0;--i)
        {
            for(int j=0;j<=i;++j)
            {
                triangle[i][j]+=min(triangle[i+1][j],triangle[i+1][j+1]);
            }
        }
        return triangle[0][0];
    }
};

题目

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

示例:

输入: [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

分析

这道经典,最长上升就是诠释动态规划不停重复试错的典范.
对于第i个元素,它最小是1,因为他自己肯定是一个,所以初始化为1.
之后就是不断试错,第i个元素依次站在0~i-1元素后面,看能不能保持上升,能的话就更新
dp[i]=max(dp[j]+1,dp[i]).
要注意到对dp的定义是以i结尾的最长的上升子序列,所以我们在每一个遍历的i都要更新ans.
(进阶版懒了,下次一定)

class Solution {
public:
    int ans=1;
    int lengthOfLIS(vector<int>& nums) {
        int sz=nums.size();
        if(sz<=1) return sz;
        vector<int> dp(sz,1);
        for(int i=1;i<sz;i++)
        {
            for(int j=0;j<i;j++)
            {
                int tmp=0;
                if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
            }
            ans=max(ans,dp[i]);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值