题目链接:https://leetcode-cn.com/problems/maximum-subarray/
经典题就需要认真做,我主要用4种方法完成本题
方法一:暴力
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
if(nums.length == 1){
return nums[0];
}
let ans = -99999;
let tmp;
for(let i = 0;i < nums.length;i++){
tmp = 0;
for(let j = i;j < nums.length;j++){
tmp += nums[j];
if(tmp > ans) ans = tmp;
}
}
return ans;
};
暴力,计算所有的子串长度,选出最长长度
方法二:动态规划
动态规划问题,弄清楚三点:
1、重复子问题;
2、最优子结构;
3、无后效性。
动态规划:
1、状态定义;
2、状态转移方程;
3、初始化;base case
4、输出;
5、思考状态压缩。
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let dp = [];
dp.push(nums[0]);
let max_len = dp[0];
for(let i = 1;i < nums.length;i++){
if(dp[i-1] > 0){
dp[i] = dp[i-1] + nums[i];
} else{
//若dp[i-1]小于0,则dp[i]加上前面的任意长度的序列和都会小于不加前面的序列
dp[i] = nums[i];
}
max_len = Math.max(dp[i],max_len);
}
return max_len;
};
定义一个数组,dp[],dp[i]以第i个元素为结尾的一段最大子序和。
求dp[i]时,假设前面dp[0]~dp[i-1]都已经求出来了,dp[i-1]表示的是以i-1为结尾的最大子序和,
若dp[i-1]小于0,则dp[i]加上前面的任意长度的序列和都会小于不加前面的序列
方法三:贪心
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let max_len = nums[0];
let sum = 0;
for(let i = 0;i < nums.length;i++){
if(sum > 0){
sum += nums[i];
}else{
sum = nums[i];
}
max_len = Math.max(max_len,sum);
}
return max_len;
};
方法四:分治法
- 最大子序列全部在数组左部分
- 最大子序列全部在数组右部分
- 最大子序列横跨左右数组
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
return helper(nums, 0, nums.length - 1);
};
function helper(nums,left,right){
if(left == right) return nums[left];
const mid = ((right - left) > 2) + left; //巧妙地计算mid
const l = helper(nums,left,mid); //左子串求出来的最大子序和
const r = helper(nums, mid + 1, right); // 右子串求出来的最大子序和
let sum = 0;
let lMax = -Number.MAX_VALUE;
let rMax = -Number.MAX_VALUE;
for (let i = mid; i >= left; i--) { //从中间开始往两边计算最大子序和
sum += nums[i];
if (sum > lMax) lMax = sum;
}
sum = 0;
for (let i = mid + 1; i <= right; i++) {
sum += nums[i];
if (sum > rMax) rMax = sum;
}
return Math.max(l, r, lMax + rMax);
}