一、题目剖析
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
示例 1:
ini
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
ini
输入: nums = [1]
输出: 1
示例 3:
ini
输入: nums = [5,4,-1,7,8]
输出: 23
给定一个整数数组 nums,任务是精准找出一个具有最大和的连续子数组(且子数组最少包含一个元素),并返回这个最大和。这里需要特别注意的是,子数组的连续性这一关键特性,它限定了子数组必须是数组中紧密相连的一部分。
二、从暴力法到 Kadane 算法的思维进阶
(一)暴力法的困境
初看题目,最容易想到的便是暴力法。这种方法的核心思路非常直观,就是通过遍历所有可能的子数组,逐一计算它们的和,然后从这些和中找出最大值。然而,这种方法存在一个严重的弊端,其时间复杂度高达 O (n²)。想象一下,当数组长度达到 10^5 这样的规模时,暴力法需要进行的计算量将是一个天文数字,这在实际应用中几乎是不可接受的。因此,我们迫切需要寻找一种更加高效的解决方案。
(二)Kadane 算法优势
幸运的是,有一种名为 Kadane 算法的高效方法专门用于解决此类问题。Kadane 算法的核心在于巧妙地维护两个关键变量:当前的最大和 currentMax 以及全局的最大和 globalMax。在算法的初始阶段,我们将这两个变量都初始化为数组的第一个元素 nums[0]。
随后,我们开始从数组的第二个元素起进行遍历。对于每一个遍历到的元素 nums[i],我们都面临着一个重要的决策:是将当前元素加入到前面已经形成的子数组中,还是以当前元素为起点重新开始一个新的子数组。这个决策过程通过 Math.max(nums[i], currentMax + nums[i]) 来实现,即比较将当前元素加入现有子数组后的和与直接以当前元素作为新子数组的和,取两者中的较大值作为新的 currentMax。
紧接着,我们通过 Math.max(globalMax, currentMax) 来更新 globalMax,确保 globalMax 始终记录着遍历过程中遇到的最大子数组和。
为了更清晰地理解这个过程,我们以示例 1 中的数组 [-2,1,-3,4,-1,2,1,-5,4] 为例进行详细说明。初始时,currentMax 和 globalMax 都被设为 -2。当遍历到第二个元素 1 时,currentMax 更新为 max(-2 + 1, 1),即 1,同时 globalMax 也更新为 1。继续遍历到第三个元素 -3,此时 currentMax 变为 max(1 - 3, -3),也就是 -2,而 globalMax 保持为 1。当遇到元素 4 时,currentMax 为 max(-2 + 4, 4),结果是 4,globalMax 随之更新为 4。如此循环往复,每一步都精准地更新 currentMax 和 globalMax,直到遍历完整个数组。
通过这种方式,Kadane 算法仅需对数组进行一次遍历,其时间复杂度成功降低至 O (n),空间复杂度更是低至 O (1),这无疑是对暴力法的一次巨大超越。
三、代码实现
下面是用 Java 实现 Kadane 算法的代码:
ini
class Solution{
public int maxSubArray(int[] nums){
int currentMax = nums[0];
int globalMax = nums[0];
for (int i = 1;i < nums.length;i++){
currentMax=Math.max(nums[i],currentMax + nums[i]);
globalMax = Math.max(globalMax, currentMax);
}
return globalMax;
}
}
代码详细解析
- 变量初始化:首先定义了两个关键变量 currentMax 和 globalMax,并将它们都初始化为数组的第一个元素 nums[0]。这一步为后续的计算奠定了基础。
- 循环遍历:通过一个 for 循环从索引 1 开始遍历整个数组 nums。在每次循环中,我们都要对 currentMax 和 globalMax 进行更新。
- 更新 currentMax:在循环内部,使用 Math.max(nums[i], currentMax + nums[i]) 来更新 currentMax。这一步的作用是根据当前元素 nums[i] 的情况,决定是将其加入现有子数组还是以它为起点创建新的子数组。
- 更新 globalMax:紧接着,通过 Math.max(globalMax, currentMax) 来更新 globalMax,确保 globalMax 始终存储着全局最大的子数组和。
- 返回结果:当循环结束后,globalMax 中存储的值就是整个数组中具有最大和的连续子数组的和,此时返回 globalMax 即可得到最终答案。
四、总结
希望通过本文的介绍,能够帮助大家对寻找最大子数组和问题有更深入的理解