题目链接
题目
输入一个整型数组,数组里🈶️正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:
- 1 <= arr.length <= 10^5
- -100 <= arr[i] <= 100
- 注意:本题与主站 53 题相同:leetcode-cn.com/problems/ma…
题解
遍历
- 时间复杂度O(n)
- 空间复杂度O(1)
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let ans = nums[0];
let sum = 0;
for(const num of nums) {
if (sum > 0) {
sum += num;
} else {
sum = num;
}
// console.log(num, sum);
ans = Math.max(ans, sum);
}
return ans;
}
贪心算法
- 时间复杂度O(n)
- 空间复杂度O(1)
从左向右迭代,一个个数字加过去,若果sum < 0, 重新开始找子序串
var maxSubArray = function(nums) {
let result = nums[0];
let sum = 0;
for(const num of nums) {
sum += num;
result = Math.max(result, sum);
if (sum < 0) {
sum = 0;
}
console.log(num, sum);
}
return result;
}
动态规划
- 时间复杂度O(n)
- 空间复杂度O(1)
f(i)的取值为:
- f(i - 1) <= 0时,取data[i]
- f(i - 1) > 0时,取f(i - 1) + data[i]
var maxSubArray = function(nums) {
let pre = 0, maxAns = nums[0];
nums.forEach((x) => {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
});
return maxAns;
};
分治
- 时间复杂度O(nlog(n))
- 空间复杂度O(log(n)) 因为调用栈的深度最多是logn
分治法的做题思路是:先将问题分解为子问题;解决子问题后,再将子问题合并,解决主问题。
我们把数组nums以中间位置(m)分为左(left)右(right)两部分. 那么有,
left = nums[0]...nums[m - 1] 和 right = nums[m + 1]...nums[n-1]
最大子序列和的位置有以下三种情况:
- 考虑中间元素nums[m], 跨越左右两部分,这里从中间元素开始,往左求出后缀最大,往右求出前缀最大, 保持连续性。
- 不考虑中间元素,最大子序列和出现在左半部分,递归求解左边部分最大子序列和
- 不考虑中间元素,最大子序列和出现在右半部分,递归求解右边部分最大子序列和
分别求出三种情况下最大子序列和,三者中最大值即为最大子序列和。
function crossSum(nums, left, right, mid) {
if (left === right) {
return nums[left];
}
let leftMaxSum = Number.MIN_SAFE_INTEGER;
let leftSum = 0;
for (let i = mid; i >= left; --i) {
leftSum += nums[i];
leftMaxSum = Math.max(leftMaxSum, leftSum);
}
let rightMaxSum = Number.MIN_SAFE_INTEGER;
let rightSum = 0;
for (let i = mid + 1; i <= right; ++i) {
rightSum += nums[i];
rightMaxSum = Math.max(rightMaxSum, rightSum);
}
return leftMaxSum + rightMaxSum;
}
/**
* @param {number[]} nums
* @param {number} left
* @param {number} right
* @return {number}
*/
function __maxSubArray(nums, left, right) {
if (left === right) {
return nums[left];
}
const mid = Math.floor((left + right) / 2);
const lsum = __maxSubArray(nums, left, mid);
const rsum = __maxSubArray(nums, mid + 1, right);
const cross = crossSum(nums, left, right, mid);
return Math.max(lsum, rsum, cross);
}
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
return __maxSubArray(nums, 0, nums.length - 1);
};
暴力
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let numsLength = nums.length;
if(!numsLength) return;
let max = nums[0];
for(let i = 0; i < numsLength; i++) {
let sum = 0;
for (let j = i; j < numsLength; j++) {
sum += nums[j];
if (sum > max) {
max = sum;
}
}
}
return max;
};