53. 最大子序和
题目描述:
给定一个整数数组 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 * 1 0 4 10^4 104
- - 1 0 5 10^5 105<= nums[i] <= 1 0 5 10^5 105
- 进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的
分治法
求解。
JAVA代码:
暴力解法:
思路:遍历数组中的所有子序列和,并挨个跟最大值比较。
缺点:冗余,遍历时间太长了。
更新:最新的超出时间限制,已经行不通了。
class Solution {
public int maxSubArray(int[] nums) {
int max =nums[0];
for(int i = 0;i<nums.length;i++){
int sum = 0;
for(int j = i;j<nums.length;j++){
sum+=nums[j];
max = sum>max?sum:max;
}
}
return max;
}
}
动态规划:
“如果我是后面的数字,我肯定希望前面传给我一个正数,给我一个负数把我变小,那我不如只要自己”
注意: sum是以 nums[i - 1] 结尾的连续子数组的和的最大值
class Solution {
public int maxSubArray(int[] nums) {
int sum = nums[0];
int max = nums[0];
//贪心算法(前面的是正数才加,否则从当前位置从新开始)
for(int i = 1;i<nums.length;i++){
sum = sum<0?nums[i]:sum+nums[i];
max = Math.max(max,sum);
}
return max;
}
}
也可以替换成sum = Math.max(sum + x, x);
意为判断加上前面的数,会不会让当前值减少。
分治法:
思路:
class Solution {
public int maxSubArray(int[] nums) {
return getMax(nums,0,nums.length-1);
}
public int getMax(int[] nums,int start,int end){
//标记递归结束
if(start == end){
return nums[start];
}
int mid = (start + end)/2;
//获取左边的最大值
int leftMax = getMax(nums,start,mid);
//获取右边的最大值
int rightMax = getMax(nums,mid+1,end);
//获取结合中间数据的最大值
//计算左边的最大值
int maxL = nums[mid];
int sumL = 0;
for(int i = mid;i>=start;i--){
sumL += nums[i];
maxL = Math.max(maxL,sumL);
}
//计算右边的最大值
int maxR = nums[mid+1];
int sumR = 0;
for(int j = mid+1;j<=end;j++){
sumR += nums[j];
maxR = Math.max(maxR,sumR);
}
//计算合体的最大值
int sum = maxL+maxR;
return Math.max(sum,Math.max(leftMax,rightMax));
}
}
分治方法的官方讲解,有些晦涩难懂。这个版本的分支方法还比较容易理解。可以看一看:
https://leetcode-cn.com/problems/maximum-subarray/solution/zheng-li-yi-xia-kan-de-dong-de-da-an-by-lizhiqiang/