题目:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
关键思路:
子数组,是连续部分,故排除排序优化。
仔细思考一下,这是一个典型的DP,分析如下:
因为可以产生递推关系, 采用动态规划时, 经常通过遍历方式, 如 背包问题, 最大公共子串 , 这里的动态规划解法也是以 先遍历出 以某个节点为结束节点的所有子序列 的思路。
对于刚接触动态规划的, 我感觉熟悉第三种遍历方式是需要抓住的核心。
因为我们通常的惯性思维是以子序列的开头为基准,先遍历出以 a 为开头的所有子序列,再遍历出以 b 为开头的...但是动态规划为了找到不同子序列之间的递推关系,恰恰是以子序列的结束点为基准的,也就是a[i],这点开阔了我们的思路。
状态转移方程:sum[i] = max{sum[i-1]+a[i],a[i]}
// 有一个数组不断的计算前序状状态。
// 简言之,就是数学里,Sn与Sn-1之间的推导关系。
在每一个扫描点计算以该点数值为结束点的子数列的最大和(正数和)
1.求出每一项与之前的和(arr)
2.负数不必再相加(负数为一个子数组的分界线)
3.正数继续相加(表示多个子数组)
4.求数组里的最大值(最后求出正数的最大值,最大子数组集合)
解:
方法1:
var maxSubArray = function (nums) {
if (!nums) {
return 0
}
if (nums.length === 1) {
return nums[0]
}
let Sn = [nums[0]];
for (let i = 1; i < nums.length; i++) {
if(Sn[i-1] + nums[i] < nums[i]) {
Sn[i] = nums[i];
} else {
Sn[i] = Sn[i-1] + nums[i]
}
}
return Math.max(...Sn)
}
将所有的历史和存储在一个list中,即维护了一个空间来存储所有的Sn,又额外的堆空间使用。
怎样调整呢?优化掉这个堆空间的使用。
方法2:
var maxSubArray = function (nums) {
if (!nums) {
return 0
}
if (nums.length === 1) {
return nums[0]
}
let Sn = nums[0];
let max = nums[0];
for (let i = 1; i < nums.length; i++) {
if (Sn + nums[i] < nums[i]) {
Sn = nums[i];
} else {
Sn = Sn + nums[i]
}
max = max > Sn ? max : Sn;
}
return max;
}
将方法一一个堆变量变成两个普通栈变量。
———— 前端、Javascript实现、算法、刷题、leetcode