【leetcode刷题】[简单]53. 最大子序和(maximum subarray)-java

本文深入探讨了最大子序和问题,通过动态规划的方法,分析了如何在给定的整数数组中找到具有最大和的连续子数组,并提供了详细的算法证明及代码实现。

最大子序和 maximum subarray

题目

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。  

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
代码模板:

class Solution {
    public int maxSubArray(int[] nums) {
        
    }
}

分析

这道题的解法非常多,有暴力的循环解法,有二分法,但是我要说一下最巧妙的算发:动态规划。
网上翻阅了一下,看到了有写的很好的论述:

引理1: 以负数开头的子序列不会是最大子序列。
证明:令子序列为{ai, ..., aj}, 其中开头的元素 ai < 0, 则 ai + ... + aj < ai+1+...+aj 显然成立。

引理2:对子序列 {ai, ..., aj} , 如果该子序列满足两个条件:

1. 如果对x取 [i, j) 中的任意整数(包含i,不包含j) sum{ai, ..., ax} >0.
2. sum{ai, ..., aj}<0.
则以该子序列中的任何元素ap开头的以aj为终结的任意子序列的和必定小于0。

证明:从两个条件中易推断出:aj<0, 且由引理1知 以负数开头的连续子序列不可能是最大连续子序列,则: ai > 0.
显然有 0 >= sum{ai, ..., aj} >= sum{ai-1, ..., aj} >= sum{ap, ..., aj}, 其中 p 是[i, j)之间的整数。
反证法:假设sum{ap, ..., aj}>0, p取 [i, j) 之间的整数, 由引理2条件 sum{ai, ..., aj}<0 得出sum{ai, ..., ap-1}<0,该结论违反了引理2中的条件:如果对x取[i, j)中的任意整数(包含i,不包含j) sum{ai, ..., ax} >0. 得证。

由引理1可知,若a[i]<0, 则应跳到a[i+1]作为子序列的开头元素(如果a[i+1]>0);
由引理2可知, 若a[i]+...+a[j]<=0且满足引理2的第一个条件,则应以a[j+1]作为最大连续子序列的开头元素(如果a[j+1]>0). 实质上,引理1是引理2的特例。
引理1和2可归结为该状态方程: maxsum(i)= max( maxsum(i-1)+ary(i), ary(i) ); (也可以由动态规划方法处理的准则:最优子结构”、“子问题重叠”、“边界”和“子问题独立”得到)
通过对给定序列顺序地反复运用引理1和引理2,最终可求得该序列的最大连续子序列。

文章出处:https://www.jianshu.com/p/04c03059e538

总结而言,temp则为之前的数的和,当然如果temp小于0的话,就归0。然后maxValue则为temp和maxValue本身的比较的最大值。我们能保证第一个数肯定是正数,

解答

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length == 1 ){
            return nums[0];
        }
        int temp = 0;
        int maxValue = nums[0];
        for(int i=0 ; i < nums.length;i++){
            temp = temp +nums[i];
            maxValue = Math.max(temp,maxValue);
            if(temp < 0){
                temp = 0;
            }
        }
        return maxValue;
    }
}
### ### 利用靈茶山艾府资源提升 LeetCode 效率 靈茶山艾府的解风格注重算法优化代码规范性,适合系统性地学习 LeetCode 。根据推荐的方法,可以结合靈茶山艾府的讲解风格,按类型并总结规律,优先从树、链表、二分查找、DFS、BFS、动态规划等常见类型入手。建议每种类型 10+ 道目,并在过程中结合靈茶山艾府的视频讲解,理解解思路代码实现方式[^1]。 靈茶山艾府在讲解目时,通常会提供清晰的图解数学推导,帮助理解复杂算法流程。例如,在滑动窗口与双指针相关的目中,靈茶山艾府会通过示例代码展示如何高效更新窗口状态,从而减少时间复杂度。类似地,在涉及贪心算法的目中,會通过排遍历的方式,以最优策略解决问。通过反复观看视频复现代码,可以逐步掌握这些技巧,并提升解效率[^3]。 对于 LeetCode 周赛中的目,建議優先選擇靈茶山艾府講解過的題目進行練習。例如,第 366 場周賽中的“Divisible and Non-divisible Sums Difference”,通過數學公式推導簡化計算過程[^1]。觀看靈茶山艾府的視頻時,注意理解其解題思路代碼優化技巧,例如在“Minimum Processing Time”問題中,通過貪心算法減少不必要的計算。 此外,靈茶山艾府的題解通常包含多種語言實現,包括 Python、Java、C++ 等,這些資源可以在 Bilibili、知乎、优快云、LeetCode 中國等平台上找到。Bilibili 上的視頻講解較為直觀,適合初學者理解算法思路;知乎 优快云 上的文章則更適合深入學習代碼實現。通過這些平台,可以系統性地學習靈茶山艾府的解題方法,並結合 LeetCode 高頻題列表進行練習。 靈茶山艾府的解題風格強調算法優化代碼可讀性,例如在“Apply Operations to Make Two Strings Equal”問題中,使用記憶化搜索避免重複計算,提高程效率。這類技巧可以應用於其他題目,提升整體解題能力。同時,在涉及數組操作的問題中,如“Minimum Size Subarray in Infinite Array”,可以採用滑動窗口法,以 O(n) 時間複雜度完成計算[^2]。 ```python # 示例代码:滑动窗口法解决数组最小长度问 def min_subarray_length(nums: list, k: int) -> int: from collections import deque dq = deque() dq.append(0) prefix_sum = [0] * (len(nums) + 1) for i in range(1, len(prefix_sum)): prefix_sum[i] = prefix_sum[i - 1] + nums[i - 1] while dq and prefix_sum[i] - prefix_sum[dq[0]] >= k: dq.popleft() return len(nums) - (dq[-1] - dq[0] + 1) ``` 靈茶山艾府的學習資源涵蓋了 LeetCode 的多個高頻題型,建議從基礎題型入手,逐步過渡到中高級難度。例如,可以從 LeetCode 周賽中的簡單題目開始,理解其數學公式推導代碼實現。隨著對解題思路的掌握,逐步挑戰更複雜的題目,如第 365 場周賽中的“Maximum Value of an Ordered Triplet I”Maximum Value of an Ordered Triplet II”。 靈茶山艾府在講解中常使用圖解數學推導,幫助理解複雜算法流程。例如,在“Make the String Great”問題中,通過滑動窗口的方式,逐步構建串並判斷是否滿足替換條件,最終找到最優解。這種思維方式可以遷移到其他類似問題中,提高解題能力。學習過程中,應注重理解算法思想而非死記硬背代碼,才能真正掌握靈茶山艾府的解題技巧。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值