news 2026/7/31 21:39:22

刷题笔记:力扣第53题-最大子数组和

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
刷题笔记:力扣第53题-最大子数组和

1.根据题目提示,最快的解法一定是遍历一遍数组、时间复杂度为O(n)的算法。既然只遍历一遍数组,那么就要至少设置三个变量,一个是指向当前元素的指针cur,一个是储存本次计算得出的和数组和curSum,一个是储存目前得出的最大子数组和maxSum。

2.思考:什么情况下需要丢弃前面一段数组呢?可以想到的是,只要前面一段数组和为正数,那么一定是带上前面这段才可能得到最大子数组和;而当前面一段数组和为负数时,丢弃掉前面这段才可能得到得到最大子数组和。那么就需要额外定义一个储存之前数组和的变量preSum。

3.具体的思路为:curSum先初始化为0,用preSum记录上次curSum的值,如果preSum< 0则丢弃掉前面一段数组,让preSum重新初始化为0。每次都计算curSum等于preSum与当前数组元素的和,让maxSum等于过去的maxSum和curSum中的较大值。遍历完整个数组后即可得出最大子数组和。

完整代码如下:

1. // 自定义宏函数,用于比较两个数的大小,返回较大值 2. #define max(a, b) a > b ? a : b 3. 4. int maxSubArray(int* nums, int numsSize) { 5. // 定义变量 6. int cur, // cur:循环计数器,遍历数组的下标 7. preSum, // preSum:之前的累计和(判断是否为负数,决定是否清零) 8. curSum = 0, // curSum:当前连续子数组的累计和 9. maxSum = nums[0]; // maxSum:记录全局最大和(初始化为数组第一个元素,处理全负数情况) 10. 11. // 遍历整个数组 12. for (cur = 0; cur < numsSize; cur++){ 13. // 1. 把上一轮的累计和赋值给 preSum 14. preSum = curSum; 15. 16. // 2. 核心贪心思想: 17. // 如果前面的累计和是负数,那么它只会拖累当前数字,所以直接舍弃前面的,从0开始 18. if (preSum < 0){ 19. preSum = 0; 20. } 21. 22. // 3. 计算以当前数字结尾的最大子数组和 23. curSum = preSum + nums[cur]; 24. 25. // 4. 更新全局最大值:比较历史最大值和当前计算出的和,保留大的 26. maxSum = max(maxSum, curSum); 27. } 28. 29. // 遍历结束,返回最终的最大和 30. return maxSum; 31. }

该算法的本质为贪心算法,时间复杂度为O(n),空间复杂度为O(1),已经是最优解。

4.力扣官方希望解题者尝试一下分治法,简单来说就是“递归切割+合并”。分治法的思路为定义一个结构体存储左端点开始的最大子数组和、右端点开始的最大子数组和,这段区间的最大子数组和以及所有元素的子数组和,之后不断用get函数进行二分,递归分割到子数组只有一个元素后开始合并,算出新的结构体元素值,最后返回合并后的完整数组的最大子数组和即可。

5.代码+解析如下:

1. // 结构体:存储一段区间的4个关键状态 2. struct Status { 3. int lSum; // 从左端点开始的最大子数组和 4. int rSum; // 以右端点结束的最大子数组和 5. int mSum; // 这段区间的【最大子数组和】(最终答案) 6. int iSum; // 这段区间所有元素的总和 7. }; 8. 9. // 核心函数:合并左右两个子区间,计算出新的大区间状态 10. struct Status pushUp(struct Status l, struct Status r) { 11. // 1. 大区间的总和 = 左区间总和 + 右区间总和 12. int iSum = l.iSum + r.iSum; 13. 14. // 2. 新的 lSum:要么是左区间自己的 lSum,要么是左区间全量 + 右区间的 lSum 15. int lSum = fmax(l.lSum, l.iSum + r.lSum); 16. 17. // 3. 新的 rSum:要么是右区间自己的 rSum,要么是右区间全量 + 左区间的 rSum 18. int rSum = fmax(r.rSum, r.iSum + l.rSum); 19. 20. // 4. 新的 mSum(最重要):三种情况取最大值 21. // 情况1:最大子数组在左区间 22. // 情况2:最大子数组在右区间 23. // 情况3:最大子数组跨越中间 24. int mSum = fmax(fmax(l.mSum, r.mSum), l.rSum + r.lSum); 25. 26. // 返回合并后的大区间状态 27. return (struct Status){lSum, rSum, mSum, iSum}; 28. }; 29. 30. // 递归函数:二分求解区间 [l, r] 的 Status 31. struct Status get(int* a, int l, int r) { 32. // 递归终止条件:区间只有一个数字 33. if (l == r) { 34. return (struct Status){a[l], a[l], a[l], a[l]}; 35. } 36. 37. // 二分:将区间从中间分成两半 38. int m = (l + r) >> 1; 39. 40. // 递归求解左半区间 41. struct Status lSub = get(a, l, m); 42. // 递归求解右半区间 43. struct Status rSub = get(a, m + 1, r); 44. 45. // 合并结果并返回 46. return pushUp(lSub, rSub); 47. } 48. 49. // 主函数入口 50. int maxSubArray(int* nums, int numsSize) { 51. // 求解整个数组 [0, numsSize-1] 的 Status,返回 mSum(答案) 52. return get(nums, 0, numsSize - 1).mSum; 53. }

其中fmax函数是C语言数学库自带的函数,作用就是输入两个数,返回较大数,和#define max(a, b) a > b ? a : b作用一样。

6.分治法的时间复杂度为O(nlogn),虽然比贪心算法速度慢,但分治法的递归思想是很重要的,也需要掌握。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 14:56:52

力扣刷题——429.N叉树的层序遍历

429.N叉树的层序遍历 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1&#xff1a;输入&#x…

作者头像 李华
网站建设 2026/7/14 14:57:00

进 程

1. 什么是进程进程是操作系统进程资源分配的基本单位&#xff0c;每一个正在运行的软件程序都对应着一个或多个进程。PCB是一个描述进程的结构体&#xff0c;操作系统中的PCB通过链表进行连接&#xff0c;对PCB的添加和删除也就是对进程的创建和消耗2. PCB的重要属性PCB中有多个…

作者头像 李华
网站建设 2026/7/14 14:57:02

Q312B三菱主基板

Q312B 是三菱电机 MELSEC-Q 系列的 12 槽主基板&#xff08;主基架 / 背板&#xff09;&#xff0c;作为 PLC 系统的核心安装与通信枢纽&#xff0c;用于安装电源、CPU 及各类 I/O/ 功能模块&#xff0c;是构建中型至大型 Q 系列控制系统的标准主平台。一、产品特性类型&#x…

作者头像 李华
网站建设 2026/7/14 14:57:00

小白程序员必看:从怕黑客到靠黑客技术赚钱(收藏版)

前言&#xff1a;从 “怕黑客” 到 “靠黑客技术赚钱”&#xff0c;我踩透了这 2 个核心问题 2022 年&#xff0c;我还是个月薪 6K 的运维&#xff0c;因为社交账号被盗&#xff0c;第一次直面 “黑客攻击”—— 看着被盗走的照片和聊天记录&#xff0c;我既愤怒又无力。那时我…

作者头像 李华
网站建设 2026/7/14 14:57:01

openclaw 本地部署ollama模型使用

进入ollama官网&#xff0c;选择windows下载&#xff0c;安装过程一路点击下一步即可根据显存大小下载相应的模型&#xff0c;下面以qwen2.5:14b为例&#xff0c;等待模型下载完成模型参数量推荐程度显存占用 (量化后)运行体验7B⭐⭐⭐⭐⭐ 完美~4-6GB (Q4)流畅&#xff0c;推理…

作者头像 李华
网站建设 2026/7/14 14:57:02

前端十年:从0到资深开发者的10堂必修课【第2篇】

前端十年&#xff1a;从0到资深开发者的10堂必修课 第2篇&#xff1a;进阶篇——JavaScript 语言精髓如果说 HTML 和 CSS 是前端的皮囊&#xff0c;那么 JavaScript 就是灵魂。掌握 JavaScript 的核心机制——作用域、闭包、原型、异步——是区分“会用”和“精通”的关键分水岭…

作者头像 李华