[LeetCode] 53. Maximum Subarray

本文探讨了LeetCode题目53的最大子数组和问题,提供了暴力解法(O(n^3)/O(n^2))、分治法(O(nlogn))及动态规划法(O(n))的不同实现方式,并对比了它们的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

             [LeetCode] 53. Maximum Subarray(Medium)

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

虽说听了两节课分治,道理是听懂了,可是在题上实践起来还是有点无从下手。刚好这道题more practice也要求用分治来写,就按照老师提供的思路来试一下呗。哦当然还是把其他做法写写,循序渐进~

1. 暴力 O(n3)/O(n2)
看起来最正常的人首先想到的最正常的思路。任意选定数组中的两个数,求出包含这两个数在内,中间所有数的和,找出和最大的一个即可。稍微一下,在第二层循环寻找末端点时利用前一次的结果,可以更快一点,不过依然不理想。
代码 O(n3)

   class Solution {
   public:
       int maxSubArray(vector<int>& nums) {
         int max=INT_MIN; //INT_MIN,表示int类型可表示的最小值
         for(int i=0;i<nums.size();i++)         
            for(int j=i,tmp=0;j<nums.size();j++,tmp=0){
                for(int k=i;k<=j;k++)
                   tmp+=nums[k];
                max=tmp>max?tmp:max;
             }
         return max;
       }
   };

代码 O(n2)

  class Solution {
  public:
      int maxSubArray(vector<int>& nums) {
          int max=INT_MIN;
         for(int i=0,tmp=0;i<nums.size();i++)           
            for(int j=i,tmp=0;j<nums.size();j++){
                   tmp+=nums[j];
                   max=tmp>max?tmp:max;
                }
        return max;
      }
   };   

2. 分治 O(nlogn)
最大子序列和可能出现在左半部分,或者右半部分,或者中间。出现在中间的话,实际上就是从中间开始往左加到最大值(后缀)和往右加到最大值(前缀)之和。所以通过递归,每次比较这三个和的大小返回最大值即可。这个思路倒也不难想,主要是怎么用递归实现不太熟,花了一点时间。递归函数数组参量一定要用引用类型,否则复制时会空间不够。
代码:

 class Solution {
   public:
   int maxSum(vector<int>& A,int left,int right)
    {
        if(left==right) return A[left];
        int center=(left+right)/2;
        int mLSum=maxSum(A,left,center),mRSum=maxSum(A,center+1,right),maxLeft,maxRight,i,tmp;

        for(i=center,maxLeft=INT_MIN,tmp=0;i>=left;i--){   //左半部分最大后缀
            tmp+=A[i];
            if(tmp>maxLeft) maxLeft=tmp;
        }
        for(i=center+1,maxRight=INT_MIN,tmp=0;i<=right;i++){ //右半部分最大前缀
            tmp+=A[i];
            if(tmp>maxRight) maxRight=tmp;
        }
        int mCSum=maxLeft+maxRight;

        return mCSum>mLSum?(mCSum>mRSum?mCSum:mRSum):mLSum>mRSum?mLSum:mRSum;
    }
     int maxSubArray(vector<int>& nums) {
        return maxSum(nums,0,nums.size()-1);
     }
   };

3. 动态规划 O(n)
最大子序列一定是这样一个序列,即再加上前一项或者后一项会使和减小。最大子序列前任意连续项之和一定为负数,即不会对所求子序列的值增大有任何贡献。从某一项开始加,此时求得连续n项子序列之和,与全局作比较。直到和为负数,可确定上一起点不是所求起点,再从下一项开始继续寻找和为整数的最大子序列,直到找到最大值。由于各子序列不重复,所以遍历一轮即可找到。
代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum=0,max=INT_MIN;
        for(int i=0;i<nums.size();i++){
            if(sum>=0) sum+=nums[i];
            else sum=nums[i];
            max=sum>max?sum:max;
        }
        return max;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值