算法系列-第九题

89 阅读2分钟

题目名称:大子数组和(连续子数组的最大和)

给你一个整数数组 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


/**

* 解法一:暴力解法(双层循环)

* 思路:求出所有可能,维护最大值 max

* 时间复杂度:O(n^2) 超标不可用

* 空间复杂度:

*/

function maxSubArray(nums: number[]): number {

const len = nums.length;

if (len === 0) return 0;

if (len === 1) return nums[0];

  


let i = 0;

let j = i;

let max = 0;

let temp = 0;

while (i < len) {

if (j === len - 1) {

i++;

j = i + 1;

temp = 0;

} else {

temp = temp + nums[j];

max = Math.max(max, temp);

j++;

}

}

  


return max;

}


/**

* 解法二:动态规划

* 思路:

* 可以用dp数组表示以下标i为终点的最大连续子数组和。

* 每次遇到一个新的数组元素,连续的子数组要么加,上变得更大,要么它本

* 身就更大,因此状态转移为dp[i] = max(dp[i - 1] + array[i], array[i])。

* 遍历数组,每次只要比较取最大值即可。

* 时间复杂度:O(n),遍历一遍。

* 空间复杂度:O(n),动态规划辅助数组长度为n

*/

function maxSubArray(nums: number[]): number {

const len = nums.length;

if (len === 0) return 0;

  


const dp: number[] = [];

dp[0] = nums[0];

let maxSum = dp[0];

  


for (let i = 1; i < len; i++) {

dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);

maxSum = Math.max(maxSum, dp[i]);

}

  


return maxSum;

}


/**

* 解法三:动态规划空间优化

* 思路:

* 我们注意到方法一的动态规划在状态转移的时候只用到了i一1的信息,没有使用整个数组的信息。

* 我们可以使用两个变量迭代来代替数组。

* 状态转移的时候更新变量y,该轮循环结束的再更新x为y即可做到每次迭代都是上一轮的dp。

* 遍历数组,每次只要比较取最大值即可。

* 时间复杂度:O(n),遍历一遍。

* 空间复杂度:O(1),常数变量

*/

function maxSubArray(nums: number[]): number {

const len = nums.length;

if (len === 0) return 0;

  


let x = nums[0];

let y = 0;

let maxSum = x;

  


for (let i = 1; i < len; i++) {

y = Math.max(nums[i], x + nums[i]);

maxSum = Math.max(maxSum, y);

x = y;

}

  


return maxSum;

}