求连续子数组的最大和

求连续子数组的最大和

一般考数组的题目,重在挖掘数字时间的规律,只要找到规律就可以写递推关系式,很容易编写基于循环的

或者是动态规划的程序。

 

第一种解法:基于sum更新的解法

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        if (array.size()==0)
            return 0;
        int summax,sum;
        for(int i=0;i<array.size();++i)
        {
            if (sum<= 0)
                sum = array[i];
            else
                sum = sum + array[i];
            if(sum > summax)
                summax = sum;
        }
    return summax;
    }
};

第二种解法:自低向上的递归

使用动态规划

F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变

F(i)=max(F(i-1)+array[i] , array[i])

res:所有子数组的和的最大值

res=max(res,F(i))

如数组[6, -3, -2, 7, -15, 1, 2, 2]

初始状态:

    F(0)=6

    res=6

i=1:

    F(1)=max(F(0)-3,-3)=max(6-3,3)=3

    res=max(F(1),res)=max(3,6)=6

i=2:

    F(2)=max(F(1)-2,-2)=max(3-2,-2)=1

    res=max(F(2),res)=max(1,6)=6

i=3:

    F(3)=max(F(2)+7,7)=max(1+7,7)=8

    res=max(F(2),res)=max(8,6)=8

i=4:

    F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7

    res=max(F(4),res)=max(-7,8)=8

   以此类推  ,,,,,,,,,,,,

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int res = array[0]; //记录当前所有子数组的和的最大值
        int maxi=array[0];   //包含array[i]的连续数组最大值
        for (int i = 1; i < array.size(); i++) {
            maxi= max(maxi+array[i], array[i]);
            res= max(maxi, res);
        }
        return res;
    }
};

上边的也可以开辟 vector<int>  dp(size,0)

然后 每次计算结果都保存在 dp[i]中,最后返回dp数组中的最大值就好!

第三种解法:分治策略

       分治策略,旨在将原先的大问题不断分解成规模小的问题,比如求最大连续子数组之和,先将原数组以中间界线分为三部分,左边是中界线左边的元素,右边是中界线右边的元素,第三部分是两边都有分布的元素的集合,因为最大连续子数组之和一定是这三部分之其中的一个,所以最后比较这三部分中最大的,就是最大连续子数组之和,也是该函数的返回值。而左边、右边的计算都继续递归分治函数,直到只有一个元素为止,而第三部分是以中间界线分别向左、向右连续相加,找出最大连续子数组之和,这是最关键的一步。

     迭代次数为n=(mid-low+1)+(high-mid),也是将原本O(n^2)算法通过分治降为O(nlogn)的主要原因。


#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int hebing(int A[],int low,int mid,int high)
{
    int sum_left=A[mid];
    int temp=0;
    for(int i=mid;i>=low;i--){
        temp+=A[i];
        if(temp>sum_left)
            sum_left=temp;
    }
    int sum_righ=A[mid];
    temp=0;
    for(int i=mid+1;i<=high;i++){
        temp+=A[i];
        if(temp>sum_righ)
           sum_righ=temp;
    }
   return sum_left+sum_righ;
}

int fenzhi(int A[],int low,int high)
{
    int max = 0;
   if(low==high){
      return A[low];
   }
   else{
       
        int mid=(low+high)/2;
        int left_max=fenzhi(A,low,mid);
        int righ_max=fenzhi(A,mid+1,high);
        int mid_max=hebing(A,low,mid,high);
        if(left_max>righ_max&&left_max>mid_max){
            return left_max;
        }

        else if(righ_max>left_max&&righ_max>mid_max){
            return righ_max;
        }
        else{
            //cout<<mid_max<<endl;
            return mid_max;
        }
       
   }

}

int mysum(vector<int> a)
{
    int size = a.size();
    vector<int> dp(size);
    dp[0] = a[0];
    for(int i=1;i<size;++i)
    {
        if(dp[i-1]<0)
            dp[i] = a[i];
        else
            dp[i] =dp[i-1] +a[i];
    }
  
    return *max_element(dp.begin(),dp.end());
}


int main()
{
    /*
    for(int i=0;i<=4;i++){
        cin>>A[i];
    }*/
    int A[] ={-1,2,-3,4,9,3};

    cout<<fenzhi(A,0,5)<<endl;
    vector<int> vec(A,A+6);
    cout<<mysum(vec)<<endl;
}

求连续子数组的最大和

   分制算法的代码也比较好理解,只是找三个最大值,同样是基于递归进行分,然后合并的时候找中间的最大值!