LeetCode 53.最大子数组和

这道题是典型的动态规划和分治法问题的考察,我初来乍到,压根不知道动态规划是啥当时,分治法最后都没咋看懂,准备以后回过头来好好再学学。

动态规划借助大佬们的题解我基本上已经看懂
原题链接如下:
53. 最大子数组和
解法0(无效解法,超时了,暴力解法):

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        //本次采用暴力解题
        int sum = 0;
        int res = nums[0];
        for(int i=0;i<nums.size();i++){
            int sum = 0;
            for(int j = i;j<nums.size();j++){
                sum += nums[j];
                res = max(res,sum);
            }
        }
        return res;
    }
};

解法1(动态规划):

把原数组nums等长度的求出其对应的dp数组,dp数组(dp[i])也就是指以第 i个数结尾的「连续子数组的最大和」。

因此我们就只需要求出dp数组中每个位置的值,然后遍历返回dp数组中的最大值就可以了。

如何求dp[i]呢?这取决于nums[i]和dp[i-1]+nums[i]的大小了,如果dp[i-1]小于0,任何数加一个小于0的数都会越来越小,所以这时候还不如就让nums[i]单独一个人的值作为dp[i],如果dp[i-1]等于0,则nums[i] = dp[i-1]+nums[i](两个随便取哪个,无伤大雅),如果dp[i-1]大于0,那肯定dp[i-1]+nums[i]更大,所以我们此时的dp[i]就取dp[i-1]+nums[i],因此我们得到动态规划转移方程:

dp(i)=max{dp(i−1)+nums[i],nums[i]}

同时注意:由于每次的dp[i]的结果,最多只需要用到dp[i-1],不需要用到更往前的数据了,所以我们没必要造成空间浪费,用一个变量pre来维护对于每个当前dp[i]所对应的dp[i-1]的值,从而让空间复杂度降低到O(1)

代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
		int pre = 0;int Max = nums[0];//切记此处初始最大dp[i]的值必须弄成dp[0]别弄成变量的默认初始值0,不然有些边界情况会不满足,也即最大dp[i]也小于0的那种情况
        for(int num:nums){
            pre = max(pre+num,num);//这里每次pre的更新之后也就是dp[i]了,这个式子生效之前,pre就是dp[i-1],生效后pre的值就就代表dp[i]
            Max = max(Max,pre);//Max变量是为了节省空间,没必要开辟一个dp[]数组,每次把更大的dp[i]的值存下来了往后比较就可以了,这个式子生效前,pre已经是dp[i]了,而Max的值是dp[0]...dp[i-1]中的最大的一个,用于和每次新生成的dp[i]进行比较
        }
        return Max;
};
执行用时:92 ms, 在所有 C++ 提交中击败了55.08%的用户
内存消耗:66.1 MB, 在所有 C++ 提交中击败了80.05%的用户
通过测试用例:209 / 209

解法2(贪心):

贪心的本质和动态规划是一样的,所以两者代码也基本雷同

贪心的基本思想就是若当前指针所指元素之前的元素之和小于0,则抛弃当前元素之前的数列,也就是用一个sum变量来维护,之前元素的sum小于0的话,任何一个数加上一个小于0的数字只会越加越小,不符合我们求最大的子序列值的思想,所以我们就可以抛弃之前的数列了,把sum的值临时赋值为当前这个元素,同时再维护一个Max变量来记录每次sum变化当中的最大值,总是和最新的sum进行比较,不断更新,从而到最后结束,能得出全过程中出现的最大的sum值,也就是我们Max变量的值

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
		int sum = 0;int Max = nums[0];
        for(int num:nums){
            if(sum<0){sum = num;}
            else{
                sum = sum+num;
            }
            Max = max(Max,sum);
        }
        return Max;
    }
};
执行用时:92 ms, 在所有 C++ 提交中击败了55.08%的用户
内存消耗:66.1 MB, 在所有 C++ 提交中击败了85.81%的用户
通过测试用例:209 / 209

本题还有分治法的解法,本人水平有限,暂时看不懂,功力再高深一点之后再来填坑。
注:本人的LeetCode刷题记录系列有许多个人思考过程,看起来会很冗杂,仅供娱乐和记录而已,不喜勿喷,大家一起努力,一起进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值