关于对leetcode53最大子序和的思考
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [0]
输出:0
示例 4:
输入:nums = [-1]
输出:-1
示例 5:
输入:nums = [-100000]
输出:-100000
提示:
1 <= nums.length <= 3 * 104
-105 <= nums[i] <= 105
- **进阶:**如果你已经实现复杂度为
O(n)
的解法,尝试使用更为精妙的 分治法 求解。
法一:穷举法:数组循环,暴力求解
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
var n =nums.length;
var max=nums[0];
for (var i = 0; i < n; i++) {
for (var j = i; j < n; j++) {
var t = 0;
for (var k = i; k <= j; k++){
t+=nums[k];
if(t>max){
max=t;
}
}
}
}
return max;
};
这种穷举法需要用到三重循环,故时间复杂度为O(n3),穷举法还可进行如下优化,使得时间复杂度优化为两重循环的O(n2)
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
var max=nums[0];
var n =nums.length;
for (var i = 0; i < n; i++) {
var t = 0;
for (var j = i; j < n; j++) {
t+=nums[j];
if(t>max){
max=t;
}
}
}
return max;
};
法二:动态规划
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
var count = new Array();
var n =nums.length;
count[0]=nums[0];
var max=count[0];
for (var i = 1; i < n; i++) {
if(count[i-1]>0){
count[i]=count[i-1]+nums[i];
}else{
count[i]=nums[i];
}
if( count[i]>max){
max = count[i]
}
}
return max;
};
此解法的时间复杂度为O(n),如需求解最大子序和的起始下标和终点下标,则可用max值从i的位置依次向前作减法,直到值等于0即为起始值。
法三:分之策略,递归求解
/**
* @param {number[]} nums
* @param {number} left
* @param {number} right
* @param {number} mid
* @return {number}
*/
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);
};