最大和子数组/最大和子序列

  最大和子数组是数组中和最大的子数组,又名最大和子序列。子数组是数组中连续的n个元素,比如a2,a3,a4就是一个长度为3的子数组。顾名思义求最大和子数组就是要求取和最大的子数组。

  

  n个元素的数组包含n个长度为1的子数组:{a0},{a1},…{an-1};

  n个元素的数组包含n-1个长度为2的子数组:{a0,a1},{a1,a2},{an-2,an-1};

  ………………………………………………………………………………………………

  n个元素的数组包含1个长度为n的子数组:{a0,a1,…,an-1};

  所以,一个长度为n的数组包含的子数组个数为n+(n-1)+…+1=n*(n-1)/2。

  第一反应就是蛮力法,穷举数组所有子数组的和并求出和的最大值。这种方法简单直观容易想到,具体又有几种不同的思路。第一种方法是先求出所有长度为1的子数组的和,再求长度为2的子数组的和,以此类推,直到求出所有长度为n的子数组的和,并在求子数组和的过程中记录和的最大值。伪代码如下:

maxSum=arr[0];//maxSum记录最大子数组和

for(i=1,i<=n;i++){//子数组长度

  for(j=0;j<n;j++){//子数组开始的位置(数组下标)

    sum=0;//sum记录当前子数组和

    for(k=j;k<n&&k<j+i;k++){//求和

      sum+=arr[k];

    }

    if(sum>maxSum) maxSum=sum;

  }

}

  第二种方法是先求所有以a[0]开始的子数组的和,再求所有以a[1]开始的子数组的和,以此类推,直到最后求出所有以a[n-1]开始的子数组的和,并在求子数组和的过程中记录和的最大值。伪代码如下:

int maxSubArraySum(int *arr,int n){

  int i,j,maxSum=arr[0],sum;

  for(i=0;i<n;i++){//子数组开始位置

    sum=0;

    for(j=i;j<n;j++){//以arr[i]开始的不同长度的子数组的和,求和是一个递进过程

      sum+=arr[j];

      if(sum>maxSum) maxSum=sum;

    }    

  }

  return maxSum;

}

  蛮力法虽然可以求得问题的解,但蛮力法通常不是我们所希望的,其时间复杂度大。我们希望找到一 种更有效的方法来解决该问题,所以需要思考问题具有的特征,拿到问题就开始写代码是最忌讳的,代码前需要三思。最大和子数组一定以数组中的某个元素a[i](0<=i<n)结束,那么我们可以先分别求出以每个元素结尾的子数组的最大和,其中的最大值就是所求的最大子数组和。后一个元素的求和需要用到前一个元素的结果,递推公式为maxSumEnd[i]=max{maxSumEnd[i-1]+a[i],a[i]},代码如下:

int maxSumArraySumD(int *arr,int n){
  int i,maxSum=arr[0];
  int *maxSumEnd;
  maxSumEnd=(int*)malloc(sizeof(int)*n);
  maxSumEnd[0]=arr[0];
  for(i=1;i<n;i++){
    if(maxSumEnd[i-1]+arr[i]>arr[i])

      maxSumEnd[i]=maxSumEnd[i-1]+arr[i];
    else

      maxSumEnd[i]=arr[i];

    if(maxSumEnd[i]>maxSum)

      maxSum=maxSumEnd[i];
  }
  free(maxSumEnd);
  return maxSum;
}

  这道题目如果我们能联想到一些数学知识就可以得到更简洁的答案,优秀的程序猿一定具有很厚的数学基础和敏捷的数学思维,但有很厚数学基础和敏捷数学思维的人不一定就是程序猿,历史证明无数优秀的数学家都变成了经济学家,计算机这个专业学到后面也就剩英语和数学了,华尔街那帮吸血鬼个个都是数学怪才。

  一个数加上一个负数和会变小,一个数加上0和保持不变,一个数只有加上一个正数和才会变大。如果最大和子数组为a[i],a[j],a[k],那么一定有a[i]+a[j]>0,如果a[i]+a[j]<=0,那么最大和子数组就是a[k]。因此,我们可以从a[0]累加求和,只要累加的和大于0就继续向后累加,如果累加的和小于0,那就舍弃掉,从下一个元素从新开始累加,并在累加过程中记录和的最大值。代码如下:

int maxSubArraySum(int *arr,int n){
  int i,maxSum=arr[0],sum=0;
  for(i=0;i<n;i++){
    sum+=arr[i];
    if(sum>maxSum){ //记录最大累加和
      maxSum=sum;
    }
    if(sum<0){//累加和小于0舍弃
      sum=0;
    }
  }
  return maxSum;
}

  或许还需给出最大和子数组,那么要在求最大和子数组的过程中记录最大和子数组的起始位置。代码如下:

int maxSubArraySumPos(int *arr,int n){
  int i,maxSum=arr[0],sum=0;
  int start=0,end=0,s=0,e=0;
  for(i=0;i<n;i++){
    sum+=arr[i];
    if(sum>maxSum){
      maxSum=sum;
      e=i;
      start=s;
      end=e;
    }
    if(sum<0){
      sum=0;
      s=i+1;
      e=i+1;
    }
  }
  printf("start=%d end=%d\n",start,end);
  return maxSum;
}

  罗马之路不顺畅,大侠们不要吝啬自己的武功秘籍,评论区为各位大侠所留。

时间: 2024-10-26 17:25:08

最大和子数组/最大和子序列的相关文章

环状连续数组,求子数组最大和

今天看到环状连续数组求子数组最大和的题目,看了几篇博客,但是好像有问题,可以举出反例.于是参考其他人的博客自己又总结下. 首先,求非环状的数组中子数组 最大和问题是一个动态规划的思想. sum[i] = max(sum(i-1) + a[i], a[i]); sum[i]代表以i元素结尾的子数组的最大和,sum[i-1]代表以i-1元素结尾的子数组的最大和,a[i]代表第i个元素的值,由此公式可得,以第i个元素结尾的子数组的最大和可以由它之前的以第i-1个元素结尾的子数组的最大和推导出.如果以i

Maximum Subarray 连续子数组最大和

Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [−2,1,−3,4,−1,2,1,−5,4],the contiguous subarray [4,−1,2,1] has the largest sum = 6. More practice: If you have figur

连续子数组最大和(转)

求一个数组的相加和最大的连续子数组 思路: 一直累加,只要大于0,就说明当前的“和”可以继续增大, 如果小于0了,说明“之前的最大和”已经不可能继续增大了,就从新开始, result=max{result+arr[i],arr[i]};显然,若result>0,则可以继续相加,否则,就重新开始. #include<stdio.h> #define INF 65535 int Maxsum(int * arr, int size) { int maxSum = -INF; int sum

一维数组子数组最大和

题目:返回一个一维整数数组中最大子数组的和. 要求: 输入一个一维整形数组,数组里有正数也有负数. 一维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 设计思想: 生成数组,生成子数组,求和,求最大值. 代码: package bao; import java.util.*; public class Msum { public static void main(String args[]) { Scanne

子数组最大和的变化

参考:http://mp.weixin.qq.com/s?__biz=MjM5ODIzNDQ3Mw%3D%3D&idx=1&mid=2649965753&scene=0&sn=787eab6fbd1f47563dd9bf4851499e79 原题 给定一个数组,我们可以找到两个不相交的.并且是连续的子数组A和B,A中的数字和为sum(A), B中的元素和为sum(B).找到这样的A和B,满足sum(A) - sum(B)的绝对值是最大的. 例如:[2, -1 -2, 1,

30、剑指offer--连续子数组最大和

题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止).你会不会被他忽悠住?(子向量的长度至少是1) 解题思路:本题时动态规划问题 dp[i]表示到以a[i]结尾的最长连续子数组的最大和 d

结对开发首尾相接数组求子数组最大和

组员:燕亚峰  20122914           王童博   20122823 一.题目及要求: 返回一个整数数组中最大子数组的和 如果数组A[0]...A[j-1]首尾相邻,允许A[i-1]...A[n-1],A[0]...A[j-1]之和最大:同时返回最大子数组的位置. 二.设计思路: 对于这题本想延用一维数组的方法,不过由于数组进行了整合,始末位置无法判断.所以此种方法断然没有实现. 可以形成一个固定长度的窗口,依次相加比较. 首先将为两种情况,一种是跨越a[n-1],a[0]的.一种

首尾相接数组求子数组最大和

一.题目及要求: 返回一个整数数组中最大子数组的和 如果数组A[0]...A[j-1]首尾相邻,允许A[i-1]...A[n-1],A[0]...A[j-1]之和最大:同时返回最大子数组的位置. 二.设计思路: 对于这题本想延用一维数组的方法,不过由于数组进行了整合,始末位置无法判断.所以此种方法断然没有实现. 小伙伴曾说延用课上学生提供的方法,形成一个固定长度的窗口,依次相加比较.这不失为一个好方法.只可惜时间复杂度不是n. 于是上网查了点资料.思想有点引用网上的了.首先将为两种情况,一种是跨

连续子数组最大和

题目来源:<剑指offer>面试题31.<编程之美>2.14 题目:输入一个整形数组,数组里有正数也有负数.数组中一个或连续多个整数组成一个子数组.求所有子数组的和的最大值 解法一:假设id代表自序列的一个起点,j代表终点.如果a[i]是负的,那么它不可能代表最优子序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过a[i+1]作起点得到改进.类似地,任何负的子序列不可能是最优子序列的前缀.比如有数组{1,-2,3,10,-4,7,2,-5}.我们试着从头道尾逐个累加数组中