leetcodeF42 连续子数组的最大和
首先暴力搜索:
public final int maxSubArray1(int[] nums) { int max = Integer.MIN_VALUE; for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums.length - i; j++) { int temp = 0; for (int k = i; k <= i + j; k++) { temp += nums[k]; } max = Math.max(max, temp); } } return max; }
* @Description nums 的大小决定问题规模,按 nums 大小分割问题
* 因为求任意子数组,按区间对 nums 进行分段
* G(start,end) 表示 start 开头, end 结尾的数组的和
* 尝试列出状态转移方程:
* G(start,end)=G(start,end-1)+nums[end]
* start==end 时,以 nums[start] 回归
* 如果建立缓存,则缓存空间类似线段树,存储了各个区间的区间和
* 但基于数组长度最大可能达到 10 的 5 次方,因此数组缓存不可取,可用 哈希表 进行缓存
int max = Integer.MIN_VALUE; public final int maxSubArray2(int[] nums) { Map<String, Integer> cache = new HashMap<String, Integer>(); for (int i = 0; i < nums.length; i++) { maxSubArray(nums, i, nums.length - 1, cache); } return max; } public int maxSubArray(int[] nums, int start, int end, Map<String, Integer> cache) { if (start == end) { max = Math.max(nums[start], max); return nums[start]; } String key = String.valueOf(start) + "," + String.valueOf(end); if (cache.keySet().contains(key)) { return cache.get(key); } int re = maxSubArray(nums, start, end - 1, cache) + nums[end]; cache.put(key, re); max = Math.max(re, max); return re; }
* @Description 上述解法还是超时了,我们尝试重新定义子问题,使子问题包含更多的运算逻辑,从而更加高效的查询缓存
* 子问题包含的运算逻辑越多,则缓存命中时,避免的运算也越多
* 子问题的定义需要我们可以找出子问题与上层问题间的状态转移关系。
* 我们可以从状态转移关系判断,该状态转移路径是否可以完整的覆盖解空间,从而回推分治子问题定义的正确性。
* G(end) 表示 end 结尾的最长子数组。
* 以 end 结尾,最长子数组有两种可能:G(end-1)+nums[end] , nums[end]
* 因此状态转移方程为:
* G(end) = Max( G(end-1)+nums[end],nums[end])
* 回推一下,最长的子数组一定是以 nums 中某一个元素结尾的
* 最大值一定在 G(0)...G( length-1 ) 中
public int maxSubArray(int[] nums) { int[] cache = new int[nums.length]; int max = Integer.MIN_VALUE; for (int i = 0; i < nums.length; i++) { max = Math.max(dp(nums, i, cache), max); } return max; } public int dp(int[] nums, int end, int[] cache) { if (end == 0) { return nums[0]; } if (cache[end] != 0) { return cache[end]; } cache[end] = Math.max(dp(nums, end - 1, cache) + nums[end], nums[end]); return cache[end]; }
转为递推表示:
public int maxSubArrayDP(int[] nums) { int[] cache = new int[nums.length]; cache[0] = nums[0]; int re = nums[0]; for (int i = 1; i < nums.length; i++) { cache[i] = cache[i - 1] < 0 ? nums[i] : cache[i - 1] + nums[i]; re = Math.max(cache[i], re); } return re; }
最终解法效率:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构