求最大子数组和(数据结构和算法C++)

题目

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

子数组 是数组中的一个连续部分。

示例 1:

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

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

来源:力扣(LeetCode)

纠错1:

第一个方法暴力解,提交以后时间复杂度超时了。。。
此外,在边界数组中的检验修改了好多次,比如[-1,2],[-1,-2],[-1]
本人吸取总结教训和经验:

  • 检验时考虑边界的特殊情况,比如数组里只有一个或两个元素,全为负数等
  • 对于求和类。int sum = 0 有负数风险,不如一开始初始化为nums[0];或者单独定义一个result变量去返回值
  • 对于for循环不清楚边界的问题,在旁边备注一个例子测试一下可取边界
  • 写函数时不要忘了写返回值。。。
  • for循环嵌套要厘清逻辑,尽量最多两层嵌套
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    int n=nums.size();//2
    int sum=nums[0];
    if (n==1)
        return nums[0];
    for (int i=0; i<n; i++)//0-1
        {
          for (int j=n-1; j>0; j--)//1
            {
                //long int subsum=std::accumulate(nums.begin()+i,nums.end()-j,0);
                int subsum=0;
                for (int m=i,n=j;m<=n;m++)//
                    {
                      subsum+=nums[m];
                      if ( sum < subsum )
                        sum = subsum;
                    };
            };
        };
        return sum;
    };
};

修改1:

超出时限- -考虑其他思路

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    int numsSize=int(nums.size());
    int result = INT_MIN;//#includ<limits>

    for (int i=0; i<numsSize; i++)
        {
          int sum = 0;
          for (int j=i; j<numsSize; j++)
            {
                  sum+=nums[j];
                  if (result < sum)
                    result = sum;
            };
        };
        return result;
    };
};

动态规划1:

需要注意的地方:

  • for循环的每条语句厘清逻辑,目的是什么,得到的值是什么
  • 返回变量的初始值设定问题,个人感觉还是设为数组[0]比较好,避免了数组只有一个元素的情况,逻辑上也不太容易出现漏洞
  • 变量命名上,注意一下如,maxSubArray
  • 用到一些库函数,如max
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    int numsSize=int(nums.size());
    //int result = INT_MIN;//声明成理论意义上的极值避免在if判断比较中出现逻辑漏洞
    int result = nums[0];
    //vector<int> maxSumArray(numsSize);//vector动态内存管理,这里仿佛不必要
    int maxSumArray[numsSize];//简单的累加,已知空间大小
    //maxSumArray.pushback(nums[0]) ;
    maxSumArray[0] = nums[0];

    for (int i=1; i<numsSize; i++)
        {
        maxSumArray[i]=max(maxSumArray[i-1]+nums[i], nums[i]);//#include<algorithm>,容易漏掉只有nums只有一个值的情况
        result= max(maxSumArray[i],result);
        };
    return result;
    };
};

动态规划的进一步优化:

class Solution
{
public:
    int maxSubArray(vector<int> &nums)
    {
        int numsSize = int(nums.size());
        //因为只需要知道dp的前一项,我们用int代替一维数组
        int dp(nums[0]);
        int result = dp;
        for (int i = 1; i < numsSize; i++)
        {
            dp = max(dp + nums[i], nums[i]);
            result = max(result, dp);
        }

        return result;
    }
};


更进一步的简化:

cppclass Solution
{
public:
    int maxSubArray(vector<int> &nums)
    {
    int n(nums.size());
    int sum2(nums[0]);
    int result = sum2;
    for (int i=1; i<n; i++)
    {
        /* 不如直接使用max函数效率高
        int sumTemp(sum2+nums[i]); 
        if (sumTemp < nums[i])
            sum2 = nums[i]; 
        else
            sum2 = sumTemp;*/
        sum2 = max(sum2+nums[i], nums[i]);
        //result = max(sum2, result);不如直接判断效率高:
        if (result < sum2)
            result = sum2;
    }
    return result;
    }
};

贪心法1:

注意点:

  • 初始值的设定一直是个问题,设定不好很容易在边界问题上出错,比如只有一个或两个元素的数组。这里的sum2设初值为0,因为在for循环中,sum2一开始就是从nums[0]开始累加的。而result是在后续的max中比较得到,这里的比较元素就是sum2和自身,因此自身的初始化也得有含义,这里要么是理论意义上的最小值,要么是初值。
  • 再说一下贪心的思想,贪心就是sum2 本来是 不断累加,然后每一次累加都与上一次的result比较得出新的result。在逻辑上,sum2累加后要是小于零的话还不如直接用下一个值(也就是0加下一个nums[i]),所以这里贪心的核心思想就是:sum2小于零时归零(result保留着清零前各步中保留的最大值)
class Solution
{
public:
    int maxSubArray(vector<int> &nums)
    {
        int n(nums.size());
        int sum2(0);
        int result(nums[0]);
        for (int i=0; i<n; i++)
        {
            sum2+= nums[i];
            result=max(sum2,result);
            if (sum2<0)
                sum2=0;
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值