[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;
}
};