编程之美之2.14 求数组的子数组之和的最大值

【题目】

一个有N个整数元素的一维数组(A[0],A[1],A[2],...A[n-1]),这个数组中当然有很多子数组,那么子数组之和的最大值是多少?

该子数组是连续的。

我们先来明确一下题意:

(1)子数组意味着是连续的。

(2)题目只需要求和,并不需要返回子数组的具体位置。

(3)数组的元素是整数,所以数组可能包含正整数,负整数或者零。

举几个例子:

数组:[1,-2,3,5,-3,2]返回8

数组:[0,-2,3,5,-1,2]返回9

数组:[-9,-2,-3,-5,-3]返回8

【解法一】

设Sum[i,...,j]为数组A中第i个元素到第j个元素的和(0<=i<=j<n),遍历所有的Sum[i,...,j]。

对每个整数对,我们都要计算x[i...j]的总和,并检验该总和是否大于迄今为止的最大总和。

/*********************************
*   日期:2014-5-19
*   作者:SJF0115
*   题目: 2.14 求数组的子数组之和的最大值
*   来源:编程之美
**********************************/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <limits.h>
using namespace std;

#define N 1001

int array[N];

int main(){
    int n,i,j,k,sum;
    //freopen("C:\\Users\\XIAOSI\\Desktop\\acm.txt","r",stdin);
    while(scanf("%d",&n) != EOF){
        //输入数据
        for(i = 0;i < n;i++){
            scanf("%d",&array[i]);
        }
        int maxSum = INT_MIN;
        // i 遍历数组起点 j 遍历数组终点
        for(i = 0;i < n;i++){
            for(j = i;j < n;j++){
                sum = 0;
                //遍历所有可能的Sum[i..j]
                for(k = i;k <= j;k++){
                    sum += array[k];
                }
                maxSum = max(maxSum,sum);
            }
        }
        printf("%d\n",maxSum);
    }
    return 0;
}

时间复杂度为O(n^3)。程序运行速度很慢。

【解法二】

x[i...j]的总和与前面已经计算出的x[i...j-1]的总和密切相关,Sum[i..j] = Sum[i...j-1]+array[j] 则可以将上面算法中最后一个循环去掉,

避免重复计算,从而使算法得以改进。

时间复杂度为O(n^2)。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <limits.h>
using namespace std;

#define N 1001

int array[N];

int main(){
    int n,i,j,k,sum;
    //freopen("C:\\Users\\XIAOSI\\Desktop\\acm.txt","r",stdin);
    while(scanf("%d",&n) != EOF){
        //输入数据
        for(i = 0;i < n;i++){
            scanf("%d",&array[i]);
        }
        int maxSum = INT_MIN;
        // i 遍历数组起点 j 遍历数组终点
        for(i = 0;i < n;i++){
            sum = 0;
            for(j = i;j < n;j++){
                sum += array[j];
                maxSum = max(maxSum,sum);
            }
        }
        printf("%d\n",maxSum);
    }
    return 0;
}

【解法三】

通过访问外循环执行之前就以构建好的数据结构的方式在内循环中计算总和。

即常见的前缀和技巧。令Sumi=A0+A1+A2+…+Ai,规定Sum0=A0,则可以在O(1)时间内求出子序列的值:Ai+Ai+1+…+Aj=Sumj-Sumi-1。这样,时间复杂度降为O(n2)。

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

#define N 1001

int array[N];
int sum[N];
int main(){
    int n,i,j;
    //freopen("C:\\Users\\XIAOSI\\Desktop\\acm.txt","r",stdin);
    while(scanf("%d",&n) != EOF){
        //输入数据
        for(i = 0;i < n;i++){
            scanf("%d",&array[i]);
            //计算前缀和
            if(i != 0){
                sum[i] = sum[i-1] + array[i];
            }
            else{
                sum[i] = array[i];
            }
        }
        int maxSum = sum[0];
        // i 遍历数组起点 j 遍历数组终点
        for(i = 0;i < n;i++){
            for(j = i+1;j < n;j++){
                maxSum = max(maxSum,sum[j] - sum[i]);
            }
        }
        printf("%d\n",maxSum);
    }
    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.(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。只需要对原数组进行一次遍历即可。

这其实是一种分治策略,时间复杂度为O(nlogn)。

编程之美之2.14 求数组的子数组之和的最大值,布布扣,bubuko.com

时间: 2024-08-01 21:11:47

编程之美之2.14 求数组的子数组之和的最大值的相关文章

【编程之美】2.14 求数组的子数组之和的最大值

做过的,就说下思路. 用Sum记录A[0...N-1]中 以第i个元素结尾的子数组中的最大和, 若以第i-1个元素结尾的子数组小于0,那么以第i个元素结尾的子数组中的最大和就是 A[i]本身 否则是A[i] + Sum(i-1的) 总结起来就是 Sum = (Sum > 0) ? A[i] + Sum : A[i]: 再记录下所有出现过的Sum中最大的值就可以了. #include <stdio.h> int getMaxSubArraySum(int * a, int alen) {

[编程之美] 2.14 求数组的子数组之和的最大值

问题描述:给定一个包含N个整数的数组,求数组的子数组之和的最大值. 这是递归和贪心策略的一个经典问题.现在,对这个问题进行一下总结. 1 明确题意 题目中的子数组要求是连续的,也就是数组中的某个连续部分. 如果数组中都是正整数,直接相加就行.因此,主要是要考虑负数的情况. 2 直接求所有的子数组和 最简单且容易理解的解法是求出所有的子数组和,然后保存最大的和. int MaxSum(int *A, int n) { int maximum = -INF; int sum = 0; int i =

编程之美2.14 求数组的子数组之和的最大值

问题描述: 一个有N个整数元素的一维数组(A[0], A[1], A[2],...,A[n-1]),这个数组当然有很多子数组,那么子数组之和的最大值是什么呢? 解法: 1. 暴力解法-------O(N^3) 2. 改进版暴力解法-------O(N^2) *3. 分治算法-------O(NlogN)(暂时未去实现) 4. 数组间关系法-------O(N) 具体思路和代码: 1.暴力解法 思路:Sum[i,...,j]为数组第i个元素到第j个元素的和,遍历所有可能的Sum[i,...,j].

2.14 求数组的子数组之和的最大值

题目:给定一个一维数组,求这个数组的子数组之和的最大值. 最佳方法:动态规划! 一. 可以将一个大问题(N个元素数组)转化为一个较小的问题(N-1个元素数组).. 假设已经知道(A[1],...A[n-1])中最大的子数组的和为:All[1] 并且已经知道(A[1],...A[n-1])中包括A[1]的子数组的最大和为start[1] 所以最终的解All[0] = max(A[0], A[0]+start[1], All[1]) 所以通过DP来求解! 代码如下: #include <iostre

编程之美 2.14求数组的子数组之和的最大值

对于一个有N个元素的数组,a[0]~a[n-1],求子数组最大值. 如:数组A[] = [−2, 1, −3, 4, −1, 2, 1, −5, 4],则连续的子序列[4,−1,2,1]有最大的和6. 方法一:暴力 循环遍历,输出所有,判断最大的和 1 #include"iostream" 2 #define MAX 1001 3 using namespace std; 4 5 int main(){ 6 int n, a[MAX], sum , maxsum ; 7 8 cin &

《编程之美》解题报告:2.14 求数组的子数组之和的最大值

引言 ? ? 本文用了五种方法来求解这道题,从最初的n^3的复杂度到后面的n的复杂度,分别用到了递推公式.分而治之以及动态规划的方法去一步步降低算法的复杂度. ? ? 解题报告 ? ? 首先我们很容易想到的一个解法就是三层遍历,首先子数组必定是连续的一串值,相当于从原数组array的下标范围0~n-1中选出i和j,去算arra[i]~array[j]的和,于是我们可以得到最初的第一个解法 ? ? public static int sol1(int[] array) { int lenght =

第2章 数字之魅——求数组的子数组之和的最大值

求数组的子数组之和的最大值 问题描述 分析与解法 [解法一] 具体代码如下: 1 package chapter2shuzizhimei.maxsumsubarray; 2 /** 3 * 求数组的子数组之和的最大值 4 * [解法一] 5 * @author DELL 6 * 7 */ 8 public class MaxSumSubArray1 { 9 //求数组的子数组之和的最大值 10 public static double maxSum(double a[]){ 11 double

求数组的子数组之和的最大值?

自己写的代码考虑未周全,引入了额外的空间复杂度: //求数组的子数组之和的最大值 #include <iostream> #define N 12 using namespace std; int main() { //int a[]={-5,2,3,-3,-2,3,1,-5}; //int a[]={-5,2,0,3,-2,3,4,5}; int a[]={1,-2,3,10,-4,7,2,-5}; int flag,max,i,j=0; int sum[N]={0}; //(1)记录子数组

求数组的子数组之和的最大值及扩展问题2

这是一道来自<编程之美>2.14节的题目. 这篇博文把思路写了一下.在此我要特别说明的是方法二和方法三的自己写的东西. 我把方法二的分治法用C++实现了一下,代码如下: int MAX(int a,int b,int c) { int t=a>b?a:b; return t>c?t:c; } int Array(int a[],int i,int j) { if (i<j) { int q=(i+j)/2,sum1=0,sum2=0,k,Max1=-0x7fffffff,Ma