C6-1 最大子数组和

题目描述

给定一个数组a[0,...,n-1],求其最大子数组(长度>=1)和

输入描述

第一行一个整数n(1<=n<=5000),然后依次输入n个整数(每个整数范围[-5000, 5000])

输出描述

输出一个整数表示最大子数组和

样例输入

5
1 -1 1 1 -1

样例输出

2

 思路;因为这道题让我们求和,那我们设置个count用于计算到目前为止的和的值,如果>0继续,若<0,则应当抛弃,否则,会影响以后的值;

 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4
 5 int max_sum(const vector<int> &array);
 6
 7 int main(){
 8     int n;
 9     cin>>n;
10     if(n<0||n>5000)   return false;
11     vector<int>array(n);
12     for(int i=0;i<n;i++){
13         cin>>array[i];
14         if(array[i]<-5000||array[i]>5000)  return false;
15     }
16     cout<<max_sum(array)<<endl;
17     return 0;
18 }
19
20 int max_sum(const vector<int> &array){
21     int sum=0;
22     int count=0;
23     for(int i=0;i<array.size();i++){
24         count+=array[i]; //将所输入的数组元素赋值给count计数
25         if(count>sum)  //若此时count>sum则将count赋值给sum
26            sum=count;
27         if(count<0)
28            count=0;  //若和为0,则将此时count置0;
29     }
30     return sum;
31 }  


解决这道题方法还有很多的方法

法1:暴力枚举法

此种方法最简单,
记sum[i..j]为数组中第i个元素到第j个元素的和(其中0<=i<j<=n-1),通过遍历所有的组合之和,就能找到最大的一个和了。
伪代码如下:

int maxSubArray(int *A,int n) {
    int maxium = -1; //保存最大子数组之和
    for i=0 to n-1 do
        sum = 0; //sum记录第i到j的元素之和
        for j=i to n-1 do
            sum += A[j];
        if sum>maxium do //更新最大值
            maxium = sum;
    return maxium;
}

此种方法的时间复杂度为O(n2),显然不是一种很好的办法。

方法二:分支界定
这里再介绍一种更高效的算法,时间复杂度为O(nlogn)。这是个分治的思想,解决复杂问题我们经常使用的一种思维方法——分而治之。
而对于此题,我们把数组A[1..n]分成两个相等大小的块:A[1..n/2]和A[n/2+1..n],最大的子数组只可能出现在三种情况:
    A[1..n]的最大子数组和A[1..n/2]最大子数组相同;
    A[1..n]的最大子数组和A[n/2+1..n]最大子数组相同;
    A[1..n]的最大子数组跨过A[1..n/2]和A[n/2+1..n]
前两种情况的求法和整体的求法是一样的,因此递归求得。
第三种,我们可以采取的方法也比较简单,沿着第n/2向左搜索,直到左边界,找到最大的和maxleft,以及沿着第n/2+1向右搜索找到最大和maxright,那么总的最大和就是maxleft+maxright。
而数组A的最大子数组和就是这三种情况中最大的一个。
伪代码如下:

int maxSubArray(int *A,int l,int r) {
    if l<r do
        mid = (l+r)/2;
        ml = maxSubArray(A,l,mid); //分治
        mr = maxSubArray(A,mid+1,r);
        for i=mid downto l do
            search maxleft;
        for i=mid+1 to r do
            search maxright;
        return max(ml,mr,maxleft+maxright); //归并
        then //递归出口
            return A[l];
}

方法三:动态规划
这算是一个经典的动态规划的题目了,如果不知道动态规划可以先不去理解这个名词。用通俗点的语言描述这个算法就是:
令cursum(i)表示数组下标以i为起点的最大连续下标最大的和,而maxsum(i)表示前i个元素的最大子数组之和。那么我们就可以推出下一个maxsum(i+1)应该为cursum(i+1)和maxsum(i)中选取一个最大值。递推式为:
cursum(i) = max{A[i],cursum(i-1)+A[i]};
maxsum(i) = max{maxsum(i-1),cursum(i+1)};
伪代码为:

int maxSubArray(int *A,int n) {
    cursum = A[0];
    maxsum = A[0];
    for i=1 to n-1 do
        /*当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。*/
        if cursum<0 do
            cursum = 0;
        cursum += A[i];
        if cursum>maxsum do
            maxsum = cursum;
    return maxsum;
}

这种算法时间复杂度只是O(n),效果非常好!

#include <iostream>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;

const int INF=0x7fffffff;
int max_sub_array(int arr[],int n,int &left,int &right)
{
    int maxium=-INF;
    int sum;
    for(int i=0;i<n;i++){
        sum=0;
        for(int j=i;j<n;j++){
            sum+=arr[j];
            if(sum>maxium){
                maxium=sum;
                left=i;
                right=j;
            }
        }
    }

    return maxium;
}
int max_sub_array(int arr[],int l,int r,int &left,int &right)
{
    if(l<r){
        int mid=(l+r)/2;
        int ll,lr;
        int suml=max_sub_array(arr,l,mid,ll,lr);
        int rl,rr;
        int sumr=max_sub_array(arr,mid+1,r,rl,rr);
        int sum_both=0;
        int max_left=-INF;
        int ml,mr;
        for(int i=mid;i>=l;i--)
        {
            sum_both+=arr[i];
            if(sum_both>max_left){
                max_left=sum_both;
                ml=i;
            }
        }
        int max_right=-INF;
        sum_both=0;
        for(int i=mid+1;i<=r;i++)
        {
            sum_both+=arr[i];
            if(sum_both>max_right){
                max_right=sum_both;
                mr=i;
            }
        }
        sum_both=max_left+max_right;
        if(suml<sumr) {
            if(sumr<sum_both) {
                left=ml;
                right=mr;
                return sum_both;
            }
            else {
                left=rl;
                right=rr;
                return sumr;
            }

        }
        else{
            if(suml<sum_both) {
                left=ml;
                right=mr;
                return sum_both;
            }
            else {
                left=ll;
                right=lr;
                return suml;
            }

        }
    }
    else {
        left=l;
        right=r;
        return arr[l];
    }
}
int max_sub_array_(int arr[],int n,int& left,int&right)
{
    int cursum=arr[0];
    int maxsum=arr[0];
    int pos=0;
    pos=0;
    for(int i=1;i<n;i++) {
//        if(cursum<0)
//            cursum=0;
        cursum+=arr[i];
        if(cursum<arr[i])
        {
            pos=i;
            cursum=arr[i];
        }
        if(cursum>maxsum)
        {
            maxsum=cursum;
            left=pos;
            right=i;
        }
    }
    return maxsum;

}
void test1()
{
    int arr[]={-2,5,3,-6,4,-8,6};
    int len=sizeof(arr)/sizeof(arr[0]);
    int left,right;
    int sum;
    cout<<"arr:";
    copy(arr,arr+len,ostream_iterator<int>(cout, " "));
    cout<<endl;
    sum=max_sub_array(arr,len,left,right);
    cout<<"method1:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;
    sum=max_sub_array(arr,0,len-1,left,right);
    cout<<"method2:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;
    sum=max_sub_array(arr,len,left,right);
    cout<<"method3:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;

}
void test2()
{
    const int LEN=10;
    int arr[LEN];
    int sign[LEN];
    srand(time(0));
    for(int i=0;i<LEN;i++){
        int val=rand()%1000;
        if(val%2==0)
            sign[i]=1;
        else
            sign[i]=-1;
    }
    for(int i=0;i<LEN;i++){
        int val=rand()%100;
        arr[i]=val*sign[i];
    }
    int left,right;
    int sum;
    int len=LEN;
    cout<<"arr:";
    copy(arr,arr+len,ostream_iterator<int>(cout, " "));
    cout<<endl;
    sum=max_sub_array(arr,len,left,right);
    cout<<"method1:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;
    sum=max_sub_array(arr,0,len-1,left,right);
    cout<<"method2:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;
    sum=max_sub_array(arr,len,left,right);
    cout<<"method3:("<<left<<","<<right<<")  ";
    cout<<"sum="<<sum<<endl;

}
int main()
{
    test2();
}

参考:http://www.cnblogs.com/xkfz007/archive/2012/05/17/2506299.html

时间: 2024-10-06 18:11:41

C6-1 最大子数组和的相关文章

软件工程课程作业(四)--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/haoying1994/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记录

lincode.41 最大子数组

最大子数组 描述 笔记 数据 评测 给定一个整数数组,找到一个具有最大和的子数组,返回其最大和. 注意事项 子数组最少包含一个数 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的这个题? Airbnb Amazon LinkedIn Cryptic Studios Dropbox Apple Epic Systems TinyCo Yelp Hedvig Zenefits Uber Snapchat Yahoo Microsoft Bloomberg Facebook Google T

分治策略 &nbsp; 最大子数组问题

递归式 递归式与分治方法是紧密相关的,因为使用递归式可以很自然地刻画分治算法的运行时间.一个递归式就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数.例如,在2.3.2节,我们用递归式描述了MERGE-SORT过程的最坏情况运行时间T(n): Θ(1)        若n=1 T(n) =                         (4.1) 2T(n/2)+Θ(n)    若n>1 求解可得T(n)=Θ(nlgn) 递归式可以有很多形式.例如,一个递归算法可能将问题划分为规模

首尾相连求最大子数组和

题目要求: 1.输入一个一维整形数组,数组里有正数也有负数. 2.一维数组首尾相接,象个一条首尾相接带子一样. 3.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值. 设计思想: 遍历数组里面的每一个数将第一个数变为最后一个数,具体算法 a[i-1]=a[i],这样又变成了一个新的一维数组,输出每个数组的最大子数组和,然后比较每个输出的和,找出最大的数 代码: import java.util.Scanner; public class shuzu { p

最大子数组问题

小渣今天再来更新一波,欢迎看众 老爷们尽情喷(批评指导) 何为最大子数组:简言之,就是一数组A[n]中从i到j的连续子序列(i,j均在(0,n)区间内),且不存在另一对(a,b)对使得A[a]+A[a+1]+.....A[b]>A[i]+A[i+1]+...+A[j] 可见:①只有在数组含有负数元素时这个问题才有探讨的价值,否则整个数组本身即是最大子数组了: ②并且,i<=j(最大子数组可能只含有一个元素) ③最大子数组可能不唯一 思路:按照二分法来做,最大子数组两端无非有三种情况: 在左半部

结对开发——返回整数数组最大子数组和2

返回整数数组最大子数组和2 为了实现“敏捷开发”的目的,老师让我们采取“迭代”的方法进行项目的开发,这不,对于周一的求最大子数组和又有了新的要求,如下: 1.延续上次的要求,这里不再赘余… 2.如果数组A[0]……A[j-1]首尾相连,允许A[i-1],……A[n-1],A[0]……A[j-1]之和最大: 3.同时返回最大子数组的位置: 4.要求程序必须能处理1000 个元素,且每个元素是int32 类型的. 一.实验设计思路 首先实现的是数组首尾相连,先存入数组,再将原数组反向存储形成环形数组

课后实验4--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/chengqiqin07/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记

lintcode 中等题:maximum subarray difference 最大子数组差

题目 最大子数组差 给定一个整数数组,找出两个不重叠的子数组A和B,使两个子数组和的差的绝对值|SUM(A) - SUM(B)|最大. 返回这个最大的差值. 样例 给出数组[1, 2, -3, 1],返回 6 注意 子数组最少包含一个数 挑战 时间复杂度为O(n),空间复杂度为O(n) 解题 刚做了数组中两个子数组和的最大值,这一题是求差,感觉上题的求解思想应该是可以用的 A B 分别是两个子数组的和,则: 所以 当A>B 的时候A越大越好 B越小越好 当A<B 的时候B越大越好 A越小越好

最大子数组之和、最大子数组之积、最长递增子序列求法

昨天做爱奇艺笔试题,最后一道编程题是求整型数组最长递增子序列,由于时间关系,没有完全写出来,今天重新来做做这一系列题. <1> 最大子数组之和 首先从最简单的最大子数组之和求取.数组里有正数.负数.零.设包含第 i 个元素的子数组的和为 Sum,则Sum的值为 Sum(i) = Sum(i-1) + arrey[i]; 显然如果arrey[i]<=0,则Sum(i)<=Sum(i-1);则必须把Sum(i)=arrey[i];同时maxSum用来保存Sum最大值.时间复杂度为o(n

(算法)最大子数组和以及最大子矩阵和

题目: 1.给定一数组,求该数组的最大子数组和: 2.给定一矩阵,求该矩阵的最大子矩阵和: 思路: 1.求数组的最大子数组和很简单,可以通过动态规划来实现,假设数组为arr: 假设dp[i]表示从0到i的数组的最大子数组和,那么递推关系式表示为: dp[0]=arr[0]; dp[i]=dp[i-1]>0?dp[i-1]+arr[i]:arr[i] 2.求矩阵的最大子矩阵和看似很难,其实也可以转化为最大子数组和的问题.假设矩阵为matrix 首先,我们求出矩阵每个位置按行叠加的结果,设叠加结果矩