最大子序和问题

简介: 最大子序和问题是从给定整数序列中找出连续子序列,使其和为所有子序列中最大值。常用贪心算法解决,通过遍历数组,动态维护当前子序和与最大子序和。若当前子序和为负,则舍弃,重新开始计算。最终得到最大子序和。例如,数组 [-2, 1, -3, 4, -1, 2, 1, -5, 4] 的最大子序和为 6。

所谓最大子序和问题,就是从给定的整数序列中找到连续的一串整数(至少包含 1 个整数),要求这串整数的和是所有整数串中最大的。


例如,[ -2, 1, -3, 4, -1, 2, 1, -5, 4 ] 是一个整数序列,其中和最大的整数串是 [ 4, -1, 2, 1 ],所有整数的和是 6。


再例如,[ -1, 4, -2 ] 是一个整数序列,其中和最大的整数串是 [4],只包含一个整数 4。


最大子序和问题可以用贪心算法解决,接下来就给大家讲解具体的实现思路。

贪心算法解决最大子序和问题

我们知道,贪心算法的核心是每次都选择当下最优的解决方案,又叫局部最优解。


以 [ -2, 1, -3, 4, -1, 2, 1, -5, 4 ] 为例,贪心算法查找最大子序和的思路是:从头遍历整个序列,对于每一个元素,如果它的存在有助于找到最大自序和,就把它加入到整形串中;反之则放弃当前元素,继续从下一个元素开始查找最大自序和。


元 素 分 析 是否选择 整数串
-2 -2 是负数,它的存在只会拉低后续元素的总和,不利于找到最大自序和 不选 [ ]
1 1 是正数,它可以进一步抬高后续元素的总和,有助于找到最大自序和 [1],和为 1
-3 [1, -3] 的和是 -2,是负数,[1, -3] 的存在只会拉低后续元素的总和,不利于找到最大子序和 不选 [ ]
4 4 是正数,它可以进一步抬高后续元素的总和,有助于找到最大子序和 [4],和为 4
-1 [4, -1] 的和是 3,是正数,[4, -1] 可以进一步抬高后续元素的总和,有助于找到最大子序和 [4, -1],和为 3
2 [4, -1, 2] 的和是 5,是正数,[4, -1, 2] 可以进一步抬高后续元素的总和,有助于找到最大子序和 [4, -1, 2],和为 5
1 [4, -1, 2, 1] 的和是 6,是正数,[4, -1, 2, 1] 可以进一步抬高后续元素的总和,有助于找到最大子序和 [4, -1, 2, 1],和为 6 
-5 [4, -1, 2, 1, -5] 的和是 1,是正数,[4, -1, 2, 1, -5] 可以进一步抬高后续元素的总和,有助于找到最大子序和 [4, -1, 2, 1, -5],和为 1
4 [4, -1, 2, 1, -5,4] 的和是 5,是正数,[4, -1, 2, 1, -5,4] 可以进一步抬高后续元素的总和,有助于找到最大子序和 [4, -1, 2, 1, -5,4],和为 5


可以看到,遍历过程中找到了很多个整数串,它们都是不同场景下查找最大子序和的最优解,其中最大的和是 6,它就是 [ -2, 1, -3, 4, -1, 2, 1, -5, 4 ] 这个序列的最大子序和。


下面是贪心算法解决最大子序和问题的伪代码:

maxSubArray(nums):

   n <- length(nums) // 获取 nums 序列的元素个数

   maxSum <- MIN_INT // 记录最大的子序和,初始值为最小的整数

   curSum <- 0 // 记录当前的子序和,初始值为0

 

   // 遍历整个数组

   for i<-0 to n:

       curSum <- curSum + nums[i]

       // 若当前整数串的和大于之前的最大结果,对结果进行更新

       maxSum <- max(curSum, maxSum)

       // 若当前整数串的和为负,对结果无益,则从 nums[i+1]开始重新查找。

       curSum <- max(0, curSum)


   return maxSum

贪心算法实现最大子序和问题

下面是用贪心算法实现最大子序和问题的 C 语言程序:

  1. #include <stdio.h>
  2. #include <limits.h>

  3. int maxSubArray(int* nums, int numsSize) {
  4. int n = numsSize;      // 获取 nums 序列的元素个数
  5. int maxSum = INT_MIN;   // 记录最大的子序和,初始值为最小的整数
  6. int curSum = 0;         // 记录当前的子序和,初始值为0

  7. // 遍历整个数组
  8. for (int i = 0; i < n; ++i) {
  9.        curSum += nums[i];  // 将当前元素加入当前子序列

  10. // 若当前子序和大于之前的最大结果,更新最大子序和
  11.        maxSum = curSum > maxSum ? curSum : maxSum;

  12. // 若当前子序和为负,对结果无益,从 nums[i+1] 开始重新查找
  13.        curSum = curSum > 0 ? curSum : 0;
  14. }

  15. return maxSum;  // 返回最终结果
  16. }
  17. int main() {
  18. int nums[] = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
  19. int numsSize = sizeof(nums) / sizeof(int);
  20. int result = maxSubArray(nums, numsSize);
  21. printf("最大子序和是 %d\n", result);
  22. return 0;
  23. }


下面是用贪心算法实现最大子序和问题的 Java 程序:

纯文本复制

  1. public class MaxSubArray {
  2. public static int maxSubArray(int[] nums) {
  3. int n = nums.length;      // 获取 nums 序列的元素个数
  4. int maxSum = Integer.MIN_VALUE;   // 记录最大的子序和,初始值为最小的整数
  5. int curSum = 0;         // 记录当前的子序和,初始值为0

  6. // 遍历整个数组
  7. for (int i = 0; i < n; ++i) {
  8.            curSum += nums[i];  // 将当前元素加入当前子序列

  9. // 若当前子序和大于之前的最大结果,更新最大子序和
  10.            maxSum = Math.max(curSum, maxSum);

  11. // 若当前子序和为负,对结果无益,从 nums[i+1] 开始重新查找
  12.            curSum = Math.max(curSum, 0);
  13. }

  14. return maxSum;  // 返回最终结果
  15. }

  16. public static void main(String[] args) {
  17. int[] nums = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
  18. int result = maxSubArray(nums);
  19.        System.out.println("最大子序和是 " + result);
  20. }
  21. }
相关文章
|
3月前
|
算法 Java C语言
弗洛伊德算法求最短路径
弗洛伊德算法用于寻找加权图中各顶点间的最短路径,适用于无向图和有向图。算法基于动态规划思想,通过枚举中间顶点来更新路径,确保最终得到最短路径。该算法要求路径权值非负,否则可能出错。
293 0
|
3月前
|
算法 Java 定位技术
迷宫问题
迷宫问题是指在给定区域内寻找从起点到终点的可行路径。可以使用回溯算法解决,通过不断尝试四个方向(上下左右)移动,若无法前进则回退,直到找到终点或遍历所有可能路径。文中还给出了C语言、Java和Python的实现代码,并展示了运行结果。
122 0
|
3月前
|
存储 算法
最小生成树的概念与思想
数据结构中的图存储结构包含顶点和边,分为连通图与非连通图。生成树是包含所有顶点、任意两点间仅有一条通路的极小连通图。最小生成树则是权值总和最小的生成树,常用于解决道路建设等实际问题,常用算法有普里姆算法和克鲁斯卡尔算法。
66 0
|
3月前
|
算法 程序员
时间复杂度和空间复杂度的概念
本文介绍了如何评估算法的执行效率和内存占用,重点讲解了时间复杂度和空间复杂度的概念及其计算方法。通过大O记法,可以量化算法的运行时间和内存使用情况,从而在不同算法间做出合理选择。
90 0
|
3月前
|
存储 算法 Java
寻找图中是否存在路径
本节介绍了如何使用并查集判断图中两个顶点之间是否存在有效路径。通过将图的边信息存储到并查集中,同一连通区域的顶点会处于同一集合。只需比较两个顶点的根节点是否相同,即可判断它们是否连通。文中提供了C语言、Java和Python的实现代码,并通过示例验证了算法的正确性。
63 0
|
3月前
|
算法 搜索推荐
分治算法的基本思想
分治算法通过将复杂问题拆分成多个独立的小问题,逐一解决后再合并结果。适合处理大规模数据,常见应用包括排序、查找最大值/最小值及汉诺塔等问题。
85 0
|
3月前
|
算法 Java C语言
汉诺塔问题
汉诺塔问题源自印度古老传说,涉及将一组圆盘从一根柱子移动到另一根,遵循特定规则。文章详细介绍了该问题的背景、解决思路以及如何使用分治算法实现,同时提供了C语言、Java和Python的代码示例。
184 0
|
3月前
|
算法
回溯算法的基本思想
本节介绍回溯算法,通过图1中从A到K的路径查找示例,说明其与穷举法的异同。回溯算法通过“回退”机制高效试探各种路径,适用于决策、优化和枚举问题。
76 0
|
3月前
|
存储 算法 Java
组合问题
组合问题是从给定的N个数中找出任意K个数的所有组合。由于组合内元素无顺序,因此[1,2]和[2,1]视为同一组合。解决组合问题常用的方法包括嵌套循环和回溯算法。嵌套循环适用于K值较小的情况,而回溯算法更适合K值较大的情况,能有效避免多层循环带来的代码复杂性和低效率问题。回溯算法通过递归实现,能动态选择元素并逐步构建组合,最终输出所有符合条件的组合结果。
107 0