版权声明:中华人民共和国持有版权 https://blog.csdn.net/Fly_Fly_Zhang/article/details/89857191
题目:
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.
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
翻译:
给定整数数组号,找到具有最大和的相邻子数组(至少包含一个数字)并返回其和。
例子:
输入:(2,1,3、4、1、2、1、5、4],
输出:6
说明:[4,-1,2,1]的和最大= 6。
跟进:
如果您已经找到了O(n)的解决方案,那么尝试使用分治方法编写另一个解决方案,这种方法更加微妙。
动态规划:O(n)
思想:
定义两个变量,一个记录历史最大连续和(max),一个记录当前最大和(maxsum)。
遍历当前数组,比较当前元素+maxsum是否大于maxsum,是的话旧更新当前最大和。
在将当前最大和历史最大和进行比较。将最大的赋值给max。
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int maxsum = nums[0];
for(int i = 1; i < nums.length; i++){
maxsum = maxsum + nums[i] > nums[i] ? maxsum + nums[i] : nums[i];
max = maxsum > max ? maxsum : max;
}
return max;
}
}
分治算法:
分治策略:将数组分成两部分,那么最大子数组会可能在以下三个部分。
- 左侧数组的最大子数组
- 右侧数组的最大子数组
- 左侧数组以右侧边界为边界的最大子数组+右侧数组以左侧边界为边界的最大子数组
class Solution {
public int maxSubArray(int[] nums) {
if(nums==null || nums.length==0)
return 0;
return subArray(nums,0,nums.length-1);
}
//进行三种操作,1,左边递归,2,右边递归,3 从mid位置开始往两边扩散找最大连续子数组的和。
private int subArray(int[] nums,int l,int r){
//退出递归条件
if(l==r)
return nums[l];
int mid=(l+r)>>1;
//将三种操作的结果进行比较,找出最大值。
return max(subArray(nums,l,mid),subArray(nums,mid+1,r),maxCross(nums,l,mid ,r));
}
//将从mid位置将数组分为两部分进行遍历,注意,只能从mid位置向两边遍历
//因为这个函数想要找的是mid角标在的连续子数组的最大值。
private int maxCross(int[] nums,int l ,int mid ,int r){
int maxL=nums[mid]; //这两个不能置0,因为有的元素小于0
int maxR=nums[mid+1];
int na=maxL;
//遍历左边,找到从mid位置连续的最大和
for(int i=mid-1 ; i>=l ;i--){
na+=nums[i];
if(na>maxL)
maxL=na;
}
int nb=maxR;
//遍历右边
for(int j= mid+1+1 ; j<=r ; j++){
nb+=nums[j];
if(nb>maxR)
maxR=nb;
}
return maxL+maxR;
}
//得到三个元素的最大值
private int max(int a,int b,int c){
return Math.max(a,Math.max(b,c));
}
}