最大子序和
給定一個序列(至少含有 1 個數),從該序列中尋找一個連續的子序列,使得子序列的和最大。
例如,給定序列 [-2,1,-3,4,-1,2,1,-5,4]
,
連續子序列 [4,-1,2,1]
的和最大,為 6
。
擴展練習:
若你已實現復雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。
很奇怪的是,百度了下分治法的時間復雜度為(n*logn),為啥它還要求用
這個算法求解的?
暴力解法就不說了
分治法解法:
思路:把數組分到足夠小,然後求解最小子數組的解,即只有一個元素的數組,解就是該值,
然後結合起來組成最優解。
註意,左子數組和右子數組結合時,有最大值三種可能:左子數組最大值,右子數組最大值,中間
存在一個更大的值。
求解中間存在一個更大值的思路,從合成數組中部,分別往左右邊延伸求左右邊最大值,加起來即可。
//leetcode解答格式
class Solution {
public:
int maxSubArray(vector<int>& nums) {
return max_divide(0,nums.size()-1,nums);
}
//分治法
int max_divide(int l,int r,vector<int>& sub_nums)
{
if(l==r)
return sub_nums[l];
else
{
int m=(l+r)/2;
int l_max=max_divide(l,m,sub_nums);
int r_max=max_divide(m+1,r,sub_nums);
int m_max=mid_divide(l,r,sub_nums);
if(l_max>=r_max && l_max>=m_max)
return l_max;
else if(r_max>=l_max && r_max>=m_max)
return r_max;
else
return m_max;
}
}
//求中間最大值
int mid_divide(int l,int r,vector<int> &sub_nums)
{
int m=(l+r)/2;
int l_max=INT_MIN;
int r_max=INT_MIN;
int sum=0;
for(int i=m;i>=l;i--)
{
sum+=sub_nums[i];
if(sum>l_max)
{
l_max=sum;
}
}
sum=0;
for(int i=m+1;i<=r;i++)
{
sum+=sub_nums[i];
if(sum>r_max)
{
r_max=sum;
}
}
return (l_max+r_max);
}
};
動態規劃:
線性掃描法,時間復雜度為O(n)
思路,設C(i)為以第i個元素結尾的最大和,
則C(i)=max{a(i),C(i-1)+a(i)}
並且當C(i-1)<0時,C(i)=a(i)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sub_max=INT_MIN;
int sum=0;
if(nums.size()==0) return 0;
for(unsigned int i=0;i<nums.size();i++)
{
sum+=nums[i];
if(sum>sub_max)
{
sub_max=sum;
}
if(sum<0)
{
sum=0;
}
}
return sub_max;
}
};
最大子序和