Maximum Subarray

class Solution {
public:
    int maxSubArray(int A[], int n) {
        int res = INT_MIN;
        int tem = 0;
        for(int i = 0; i < n; ++i)
        {
            tem = max(A[i],tem + A[i]);
            res = max(res,tem);
        }
        return res;
    }
};


状态转移方程:

dp[i] = max(a[i],dp[i-1] + a[i])

记住一个局部最大和一个全局最大就可以了

 为了能够找到 起始和终止位置 加一个记录就可以了

用这个改的代码通过了杭电的这个题目 应该没问题的

#include <iostream>
#include <cstdio>
using namespace std;


class Solution {
public:
    Solution()
    {
        start = end = 0;
    }
    int start,end;
    int maxSubArray(int A[], int n) {
        int res = INT_MIN;
        int tem = 0;
        int start_fake = 0,end_fake = 0;
        for(int i = 0; i < n; ++i)
        {
            //tem = max(A[i],tem + A[i]);
           // res = max(res,tem);
           if(A[i] <= tem + A[i])
           {
               tem = tem +A[i];
               end_fake = i;
           }
           else
           {
               tem = A[i];
               start_fake = i;
               end_fake = i;
           }
           if(res <= tem)
           {
                res = tem;
                start = start_fake;
                end = end_fake;
           }
        }
        return res;
    }
};

int main()
{

   // freopen("in.txt","r",stdin);
//    int a[9] = {-2,1,-3,4,-1,2,1,-5,4};
//    Solution s;
//    cout<<s.maxSubArray(a,9)<<endl;
//    cout<<s.start<<endl<<s.end<<endl;
    int T;
    int a[100000];
    cin>>T;
    for(int i = 1;i <= T ;++i)
    {

        int N;
        Solution s;
        cin>>N;
        for(int j = 0;j < N ;++j)
        {
            cin>>a[j];
        }
        cout<<"Case "<<i<<":"<<endl;
        cout<<s.maxSubArray(a,N)<<" ";
        cout<<s.start + 1<<" ";
        cout<<s.end + 1<<endl;;
        if(i != T)cout<<endl;
    }

    return 0;
}

这个是以前ac这题的代码

思想差不多

#include <iostream>

using   namespace  std;


int  main()
{
    int T,N;
    int sum,max;
    int a,start,end;
    cin>>T;
    for(int i = 1;i <= T;i++)
    {
        cin>>N;
        start = end  =1;
        sum = 0,max = -9999;
        for(int j = 1,k = 1;j <=N;j++)
        {
            cin>>a;
            sum += a;
            if(sum > max){max = sum; start = k;end = j;}
            if(sum < 0){sum = 0;k = j + 1;}
        }
        cout<<"Case "<<i<<":"<<endl<<max<<" "<<start<<" "<<end<<endl;
        if(i < T)cout<<endl;
    }

    return  0;
}

今天又看到一个分治的方法

思路:分治
如果将所给数组(A[0],...,A[n-1])分为长度相等的两段数组(A[0],...,A[n/2-1])和(A[n/2],...,A[n-1]),分别求出这两段数组各自最大子段和,
则原数组(A[0],...,A[n-1])的最大子段和分为以下三种情况,要么在前半部分a中,要么在后半部分b中,要么跨越a和b之间的边界:
a.(A[0],...,A[n-1])的最大子段和与(A[0],...,A[n/2-1])的最大子段和相同;
b.(A[0],...,A[n-1])的最大子段和与(A[n/2],...,A[n-1])的最大子段和相同;
c.(A[0],...,A[n-1])的最大子段跨过其中间两个元素A[n/2-1]到A[n/2];

对应a和b两个问题是规模减半的两个相同的子问题,可以用递归求得。

对于c,需要找到以A[n/2-1]结尾的最大的一段连续数组之和S1=(A[i],...,A[n/2-1])和以A[n/2]开始的最大的一段连续数组之和S2=(A[n/2],...,A[j]),那么第三种情况的最大值为S1+S2。
只需要对原数组进行一次遍历即可。在a中的部分是a中包含右边界的最大子数组,在b中的部分是b中包含左边界的最大子数组。
这其实是一种分治策略,时间复杂度为O(nlogn)。

http://ask.julyedu.com/question/129

http://blog.csdn.net/sunnyyoona/article/details/43200983

模仿着写了一遍 也很好理解

class Solution {
public:
    int maxSubArray(int A[], int n) {
        return  divide(A,0,n-1);
    }
    int divide(int A[],int left,int right)
    {
        if(left > right)return 0;
        if(left == right)return A[left];//递归出口
        //先把有交叉的两部分算出来
        int mid = (right -  left) / 2 + left;
        int sum = 0,left_max = INT_MIN;
        for(int i = mid;i>=left;i--)
        {
            sum += A[i] ;
            left_max = max(sum,left_max);
        }
        sum = 0;
        int right_max = INT_MIN;
        for(int i = mid +1;i <= right;i++)
        {
            sum += A[i];
            right_max =max(sum,right_max);
        }
        int a = divide(A,left,mid);
        int b = divide(A,mid+1,right);
        int c = left_max + right_max;
        return max(max(a,b),c);
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值