1. 程式人生 > >最大子序和

最大子序和

AR 分治法 ret 最大和 子序列 else 時間復雜度 sig 子數組

給定一個序列(至少含有 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;
}
};

最大子序和