[LeetCode] 53. Maximum Subarray

来源:互联网 发布:网络兼职诈骗怎么判刑 编辑:程序博客网 时间:2024/06/06 17:18
             [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;    }};
0 0
原创粉丝点击