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

  一个有N个整数元素的一维数组A[0],A[1],......,A[n-1],这个数组当然有很多子数组,那么子数组的最大值是什么呢?

分析与解法

  我们先明确题意:

  1. 题目说的子数组,是连续的;

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

  3. 数组中的元素是整数,所以数组可能包含有正整数、零、负整数;

  4. 子数组不为空。

解法一:枚举

  最简单的办法就是枚举所有的i和j,计算sum[i..j] = A[i]+A[i+1]+...+A[j],遍历所有可能的sum[i..j],找到最大值,时间复杂度为O(N3)。

  注意到sum[i..j] = sum[i..j-1]+A[j],则可以改进求和,使得时间复杂度为O(N2)。

解法二:分治

  给定数组A[0],A[1],......,A[n-1]的最大子段和,分为三种情况:

  (1) 与左半部分,即A[0],A[1],......,A[n/2-1]的最大子段和相同;

  (2) 与右半部分,即A[n/2],......,A[n-1]的最大子段和相同;

  (3) 跨过中间两个元素A[n/2-1]和A[n/2]。

  前两种情况是与原问题相同的规模较小的问题,可以递归求解,第三种情况可以遍历一遍数组即可求得,时间复杂度为O(NlogN)。

解法三:动规

  用变量sum表示以arr[i]结尾的子数组的最大和,则所求最大和ret = max{sum}

  根据如下递推关系,只需要遍历一遍数组即可:

  sum = max{arr[i], arr[i]+sum}

  ret = max{ret, sum}

  参考代码如下所示:

 1 #include <iostream>
 2 using namespace std;
 3
 4 const int maxn = 1007;
 5 int arr[maxn];
 6
 7 int maxSum(int arr[], int n)
 8 {
 9     int ret = arr[0], sum = arr[0];
10     for (int i = 1; i < n; i++)
11     {
12         sum = (sum > 0) ? (sum + arr[i]) : arr[i];
13         ret = (ret > sum) ? ret : sum;
14     }
15     return ret;
16 }
17
18 int main(int argc, char *argv[])
19 {
20     int n;
21     while (cin >> n)
22     {
23         for (int i = 0; i < n; i++)
24         {
25             cin >> arr[i];
26         }
27         int maxsum = maxSum(arr, n);
28         cout << maxsum << endl;
29     }
30 }

扩展问题

1. 如果数组是首尾相邻的,也就是我们允许找到一段数字A[i],...,A[n-1],A[0],...,A[j],请使其和最大,怎么办?

  解答:可以分为两种情况:

  (1) 解没有跨过A[n-1]到A[0](原问题);

  (2) 解跨过A[n-1]到A[0]。

  第二种情况又有两种情况,即包含整个数组和不包含整个数组,遍历数组即可求解。

  当然,对于不包含整数数组的情况,相当于从数组中删除A[j+1]...A[i-],这部分的和一定是负的,且是可能找到的子数组的和为负数且绝对值最大的。寻找这样的子数组的问题跟情形(1)是一样的,可以用同样的方法解决。

  最后,取两种情况的最大值即可。

2. 如果题目要求同时返回最大子数组的位置,算法应如何变?还能保持O(N)的时间复杂度么?

时间: 2024-10-01 07:01:57

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

编程之美之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 [解法一

[编程之美] 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].

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

自己写的代码考虑未周全,引入了额外的空间复杂度: //求数组的子数组之和的最大值 #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章 数字之魅——求数组的子数组之和的最大值

求数组的子数组之和的最大值 问题描述 分析与解法 [解法一] 具体代码如下: 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

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.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) {