007求数组中子数组最大的和

来源:互联网 发布:淘宝买的steam游戏礼物 编辑:程序博客网 时间:2024/05/06 05:13

题目描述:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。

思路一,暴力法。通过三层循环,找出所有子数组,求和,比较,得出最大和,时间复杂度O(n^3)

int maxsum01(int array[],int n){int sum = 0;int max = 0;for(int i=0;i<n;i++){for(int j=i;j<n;j++){for(int k=i;k<=j;k++){sum += array[k];}if(sum>max)max = sum;sum=0;}}return max;}
思路二,线性遍历数组,如果将当前元素加入之后sum<=0,说明截至到该元素,往后再加元素也不会达到子数组和最大,此时将sum更换为下一个元素,每次加入新元素之后都会与现有的max进行比较,以保留最大值。时间复杂度O(n)

int maxsum02(int array[],int n){int sum = 0;int max = array[0];for(int i=0;i<n;i++){if(sum>=0){sum += array[i];}else{sum = array[i];}if(sum>max)max = sum;}return max;}

当数组元素全为负数时,返回数组中最大元素值。

思路三,利用动态规划的方法

设sum[i] 为前i个元素中,包含第i个元素且和最大的连续子数组,result 为已找到的子数组中和最大的。对第i+1个元素有两种选择:做为新子数组的第一个元素、放入前面找到的子数组。
sum[i+1] = max(a[i+1], sum[i] + a[i+1])
result = max(result, sum[i])

int maxsum03(int array[],int n){int sum = array[0];int max = array[0];for(int i=1;i<n;i++){sum += array[i];if(sum < array[i])sum = array[i];if(max<sum)max = sum;}return max;}

问题扩展

  1. 如果数组是二维数组,同样要你求最大子数组的和列?
  2. 如果是要你求子数组的最大乘积列?《???
  3. 如果同时要求输出子段的开始和结束列?
对于第二题,有一个题目可以参考《给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中最大的一组》

思路是使用线性扫描,使用空间换时间,用数组b[i]保存a[0]*...*a[i-1]*a[i+1]*...a[n-1]。代码如下:

int makeArray(int a[],int b[],int n){b[0]=1;for(int i=1;i<n;i++){b[0] *= a[i-1];b[i] = b[0];//b[i]=a[0]*...*a[i-1]}b[0]=1;for(int j=n-2;j>0;j--){b[0] *= a[j+1];b[j] *= b[0];//b[j]=a[n-1]*...*a[j+1]*a[j-1]*...*a[0]}b[0] *= a[1];int max = -2147483647 - 1;cout<<endl;for(int k=0;k<n;k++){cout<<b[k]<<endl;if(max < b[k])max = b[k];}cout<<endl;return max;}

举一反三

1 给定整型数组,其中每个元素表示木板的高度,木板的宽度都相同,求这些木板拼出的最大矩形的面积。并分析时间复杂度。

此题类似leetcode里面关于连通器的题,需要明确的是高度可能为0,长度最长的矩形并不一定是最大矩形,还需要考虑高度很高,但长度较短的矩形。如[5,4,3,2,4,5,0,7,8,4,6]中最大矩形的高度是[7,8,4,6]组成的矩形,面积为16。

解决思路:使用分治递归的方法,即在[start,end]区域计算出矩形的面积,计算左侧的面积,计算右侧的面积,找出三者中面积最大的,返回

//最大值  int MAX(int a,int b) {     return a > b ? a : b; } //给定数组表示单位宽度木板的高,求最大矩形的面积 int MaxSquare(int*a,int start,int end,int &Max) {     if(end < start)         return 0;     if(end == start)         return a[end];      int minindex = start;     for(int i = start;i <=end;i++)//每次求出区间的最小高度         if(a[i] < a[minindex])             minindex = i;     int all = a[minindex] * (end - start +1);//以最小高度的最长矩形的面积     int lf = MaxSquare(a,start,minindex -1,Max);//左区域的最大面积     int rg = MaxSquare(a,minindex +1,end,Max);//右区域的最大面积     int t =MAX(all,MAX(lf,rg));//当前区间的最大面积     Max = MAX(Max,t);     return t; }  int MaxSquare(int*a,int n) {     int minindex = 0;     int max = 0;     MaxSquare(a,0,n-1,max);     return max; } 


2、最大子矩阵和

一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值。如果所有数都是负数,就输出0。 例如:3*5的矩阵:

1 2 0 3 4

2 3 4 5 1

1 1 5 3 0

和最大的子矩阵是:

4 5

5 3

最后输出和的最大值17。

原题目给出的答案可能有问题,对于子矩阵

3 4 5

1 5 3

的值要比给出的矩阵的和要大

解决思路:在求最大子数组和的基础上,对于矩阵从i到j行,相加,得到一个数组,求出a[i][0-m]到a[j][0-m]之间和最大的子矩阵的和

int maxSubMatrix(int matrix[5][5],const int n,const int m){int i,j,k,max=0,sum=-10000;int b[101];for(i=0;i<n;i++){for(k=0;k<m;k++){b[k] =0;}for(j=i;j<n;j++){for(k=0;k<m;k++){b[k] += matrix[j][k];}max = maxsum03(b,m);if(max > sum){sum = max;}}}return sum;}


3、允许交换两个数的位置 求最大子数组和。(???

// you can also use includes, for example:#include <algorithm>int help(vector<int> &a) {    int n = a.size();    vector<int> f,g;    f.resize(n);    f[0] = a[0];    int now = a[0];    for (int i = 1; i < n; ++i) {        now = max(now, a[i]);        f[i] = max(a[i] + f[i - 1], now);    }    g.resize(n);    g[n - 1] = a[n - 1];    int answer = a[n - 1];    for (int i = n - 2; i >= 0; --i) {        g[i] = max(g[i + 1], 0) + a[i];        answer = max(answer, g[i]);    }    for (int i = 1; i < n; ++i) {        answer = max(answer, g[i] - a[i] + f[i - 1]);    }    return answer;}int solution(vector<int> &A) {    // write your code in C++11    int answer = help(A);    for (int i = 0, j = A.size() - 1; i < j; ++i,--j) {        swap(A[i],A[j]);    }    answer = max(answer,help(A));    return answer;    }




0 0
原创粉丝点击