案例
...大约 3 分钟
最大子数组和(中)
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组
是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
**进阶:**如果你已经实现复杂度为 O(n)
的解法,尝试使用更为精妙的 分治法 求解。
解题思路
这个函数的核心思想是使用一个变量pre
来跟踪当前子数组的和,并在每次迭代中更新这个变量。另一个变量maxAns
用于跟踪到目前为止找到的最大子数组的和。通过遍历数组并更新这两个变量,我们可以找到最大的子数组和。这个算法的效率很高,时间复杂度为O(n),其中n是数组的长度。
var maxSubArray = function (nums) {
// 初始化pre为0,表示当前子数组的和。
// 初始化maxAns为数组的第一个元素,作为当前的最大子数组的和。
let pre = 0, maxAns = nums[0];
// 使用forEach循环遍历数组中的每个元素。
nums.forEach((x) => {
// 更新pre为当前元素加上pre或pre本身中的最大值。
// 这样可以避免负数对当前子数组的和产生负面影响。
pre = Math.max(pre + x, x);
// 更新maxAns为maxAns和pre中的最大值。
// 这样可以跟踪到目前为止找到的最大子数组的和。
maxAns = Math.max(maxAns, pre);
});
// 循环结束后,maxAns将包含最大子数组的和。
// 返回这个最大子数组的和。
return maxAns;
};
环形子数组的最大和(中)
给定一个长度为 n
的环形整数数组 nums
,返回 nums
的非空 子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i]
的下一个元素是 nums[(i + 1) % n]
, nums[i]
的前一个元素是 nums[(i - 1 + n) % n]
。
子数组 最多只能包含固定缓冲区 nums
中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], ..., nums[j]
,不存在 i <= k1, k2 <= j
其中 k1 % n == k2 % n
。
示例 1:
输入:nums = [1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3
示例 2:
输入:nums = [5,-3,5]
输出:10
解释:从子数组 [5,5] 得到最大和 5 + 5 = 10
示例 3:
输入:nums = [3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3
提示:
n == nums.length
1 <= n <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
解题思路

var maxSubarraySumCircular = function (nums) {
let maxS = Number.MIN_SAFE_INTEGER; // 最大子数组和,不能为空
let minS = 0; // 最小子数组和,可以为空
let maxF = 0, minF = 0, sum = 0;
for (const x of nums) {
// 以 nums[i-1] 结尾的子数组选或不选(取 max)+ x = 以 x 结尾的最大子数组和
maxF = Math.max(maxF, 0) + x;
maxS = Math.max(maxS, maxF);
// 以 nums[i-1] 结尾的子数组选或不选(取 min)+ x = 以 x 结尾的最小子数组和
minF = Math.min(minF, 0) + x;
minS = Math.min(minS, minF);
sum += x;
}
return sum === minS ? maxS : Math.max(maxS, sum - minS);
};
Powered by Waline v3.3.0