连续最大字段和问题

最大子段和问题描述

给定由 n 个整数(可能为负整数)组成的序列a1,a2,a3...an,求该数列中连续子段和最大!

    例如:当(a1,a2,a3,a4,a5)=(-2,11,-4,13,-5,-2)时,最大字段和为 20 (11 + (-4) + 13);

       以下例子都是以int data[6] = {-2,11,-4,13,-5,-2};    int n = 6;

 初始化数组: 

1
2
//初始化数组
private static Integer[] array = {-2, 11, -4, 13, -5, -2};

算法一:对所有满足0<=i<=j<=n的(i,j)整数对进行迭代,对每个整数对,程序都要计算array[i...j]的总和,并检验该总和是否大于迄今为止的最大总和

这段代码简洁明了,便于理解,但是程序执行的速度很慢,时间复杂度为O(n^3)

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
   * 时间复杂度为 O(n^3)
   */
  public static Integer maxSum1() {
      int maxSum = 0;             //存储最大子段和
      int tempSum;                //临时存储最大子段和
      for (int i = 0; i < array.length - 1; i++) {
          for (int j = i; j < array.length; j++) {
              tempSum = 0;
              for (int k = i; k <= j; k++) {
                  tempSum += array[k];
                  if (tempSum > maxSum) {
                      maxSum = tempSum;
                  }
              }
          }
      }
      return maxSum;
  }

  

算法二:对于算法一有一个明显的缺点,大量的计算重复。大家可以注意到:

这段代码简洁明了,便于理解,相比算法一程序执行的速度较快,时间复杂度为O(n^2)

  注意:array[i...j]的总和与前面计算出的总和(array[i...j-1])密切相关,只需要在其基础上累加即可,无需大量重复计算!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 时间复杂度为 O(n^2)
 */
public static Integer maxSum2() {
    int maxSum = 0;             //存储最大子段和
    int tempSum;                //临时存储最大子段和
    for (int i = 0; i < array.length - 1; i++) {
        tempSum = 0;
        for (int j = i; j < array.length; j++) {
            tempSum += array[j];
            if (tempSum > maxSum) {
                maxSum = tempSum;
            }
        }
    }
    return maxSum;
}

  

算法三:可以采用分治算法求解,采用二分法进行二分,然后进行递归求解,分别求出左边连续子段和最大值,右边连续子段和最大值,以及左边和右边连续子段和最大值之和,三者进行比较,从中选择一个最大值进行返回!(这个值即就是当前划分的小区间中最大值)

  注意:这段代码不太便于理解,但是程序相对于算法二执行的速度快,时间复杂度为O(n*logn)

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
   * 采用分治算法
   * 时间复杂度为 O(n*logN)
   */
  public static Integer maxSum3(int left, int right) {
      int maxSum = 0;
      if (left == right) {    //递归结束条件
          if (array[left] > 0) {
              maxSum = array[left];
          } else {
              maxSum = 0;
          }
          return maxSum;
      }
 
      int mid = (left + right) / 2;
      int leftMaxSum = maxSum3(left, mid);             //递归求解左部分最大值
      int rightMaxSum = maxSum3(mid + 1, right);  //递归求解右部分最大值
 
      //求解左边最大值和右边最大值之和
      int leftMax = 0;        //记录左边最大值
      int leftMaxTemp = 0;    //记录左边最大值的临时变量
      for (int i = mid; i >= left; i--) {
          leftMaxTemp += array[i];
          if (leftMaxTemp > leftMax) {
              leftMax = leftMaxTemp;   //左边最大值放在 leftMax
          }
      }
      int rightMax = 0;
      int rightMaxTemp = 0;
      for (int j = mid + 1; j <= right; j++) {
          rightMaxTemp += array[j];
          if (rightMaxTemp > rightMax) {
              rightMax = rightMaxTemp;  //右边最大值放在 rightMax
          }
      }
      maxSum = leftMax + rightMax;//(左边最大值和右边最大值之和)计算第 3 种情况的最大子段和
      //比较(左边最大值)和(右边最大值)以及(两边最大值之和)进行比较,从中选择一个最大值返回
      if (maxSum < leftMaxSum) {
          maxSum = leftMaxSum;
      }
      if (maxSum < rightMaxSum) {
          maxSum = rightMaxSum;
      }
      return maxSum;
  }

  

算法四:使用动态规划来求解 ,由data[]数组我们易知,当maxSumTemp > 0时,maxSumTemp = data[i] + maxSumTemp (越加越大),否则maxSumTemp = data[i](不然越加越小)

  这段代码便于理解,但是程序相对于算法三执行的速度最快,时间复杂度为O(n)

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 时间复杂度为 O(n)
 */
public static Integer maxSum4() {
    int maxSum = array[0];
    int maxSumTemp = array[0];  //初始化
 
    for (int i = 1; i < array.length; i++) {
        if (maxSumTemp > 0) {           //最大值临时变量只有大于零,才可能越加越大
            maxSumTemp += array[i];
        } else {                        //最大值临时变量只有小于零,直接等于data[i],否则越加越小
            maxSumTemp = array[i];
        }
        if (maxSumTemp > maxSum) {      //判断赋值
            maxSum = maxSumTemp;
        }
    }
    return maxSum;
}

  

测试代码:

1
2
3
4
5
6
7
public static void main(String[] args) {
//        Integer maxSum = maxSum1();
//        Integer maxSum = maxSum2();
//        Integer maxSum = maxSum3(0, array.length - 1);
        Integer maxSum = maxSum4();
        System.out.println("maxSum = " + maxSum);
    }

  每天进步一点点,日记月累就会变成大牛!

posted @   菜鸟的奋斗之路  阅读(1634)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示