终于收到offer啦!无比开心!但想到自己这么🥦恐怕去到公司会很难熬,就感觉压力好大。前天和昨天都在外面,忙着跟朋友见面什么的,以至于这一篇文章拖到了今天,果然不能提前立flag。明天写JS转换的东西吧。
这是Leetcode上面的一道简单题,题目如下。(吐槽:一点都不简单呀)
53. Maximum Subarray
Given an integer array
nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.Example:
Input: [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6.
在这里介绍三种效率比较高的方法:分治法,动态规划,和 Kadane算法。
一、分治法
顾名思义,分治法的思路是分而治之。也就是,我们要找到最大连续子数组,可以先把整个数组分成左右两份,最大子数组可能在左边子数组,可能在右边子数组,也可能穿过左右两边。然后只要找出这三种情况中的最大值,就可以得到答案。对于前两种情况,可以依次用递归的方法,分别找出。对于第三种情况,可以从中间开始,分别往左右两边找,不断相加,直到再加最值会减少。
var maxSubArray = function(nums){
//base case:当nums长度为1和0时,分别返回第一个元素和负无穷。
if(nums.length===1) return nums[0];
if(nums.length===0) return -Infinity;
//得到中间元素的index
let mid=Math.floor(nums.length/2);
//找到左边和右边的最大
let leftMax=maxSubArray(nums.slice(0,mid));
let rightMax=maxSubArray(nums.slice(mid));
//计算穿过中间元素的最大
let midLeftMax=0;
let midRightMax=0;
let currMax=0;
//计算左边的最大值
for(let i=mid-1;i>=0;i--){
currMax=currMax+nums[i];
midLeftMax=Math.max(midLeftMax,currMax);
}
//计算右边的最大值
currMax=0;
for(let i=mid+1;i<nums.length;i++){
currMax=currMax+nums[i];
midRightMax=Math.max(midRightMax,currMax);
}
//返回三个值中最大的那个
return Math.max(leftMax,rightMax,midLeftMax+nums[mid]+midRightMax);
};
二、动态规划
直接上代码,思路写在注释里。
//DP way:
//设数组中一共有n个元素,最大连续子数组可以包含以下三种情况:
// 1.最大值出现在第n个元素上
// 2.最大值为前0到n个元素的和
// 3.最大值为前0到n-1个元素的和
//当为情况3时,又可以按照上面的方法来考虑这个问题
var maxSubArray = function(nums){
//我们用两个变量来储存在过程中求得的最大和。
//max表示前k个元素中的最大和,prev表示包括k元素的前k个元素的最大和
if(nums.length===1) return nums[0];
let max=nums[0];
let prev=nums[0];
for(let i=1;i<nums.length;i++){
//当前k个元素最大和,要么是第k个元素更大,要么是前k-1个元素加上第k个元素更大
prev=Math.max(nums[i],prev+nums[i]);
//前k元素总的最大和,要么是包括当前第k元素的数组和最大,要么是前k-1个元素的和为最大
max=Math.max(prev,max);
}
return max;
};
三、Kadane算法
这个算法也运用了动态规划的思路,重点是考虑和的增加和减少。 时间不够了,下次再补充吧。