LeetCode官方题解:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode/
目录
一、需求
A:给定一个整数数组nums,找到一个具有最大和的连续子数组(最少包含一个元素);
B:返回子数组的最大和;
二、分治算法
-
思路分析
A:定义方法,递归求最大子序列和,返回值类型为int,参数列表为数组名,起始索引和结束索引;
B:递归结束条件是当只有一个元素的时候,直接返回该元素;
C:定义中间值mid=left+(right-mid)/2,先求左子数组最大值,然后求右子数组最大值;
D:求出横跨序列前半部分的最大和,以及横跨序列后半部分的最大和,并将此二者相加;
E:最后对C和D中共三个最大值进行比较,返回最大的那个;
-
代码实现
public int maxValue(int[] nums,int left,int right) {
//定义左右子数组最大值
int maxLeftSum=0, maxRightSum=0;
//定义横跨序列左右两边最大值
int maxLeftBorderSum=Integer.MIN_VALUE, maxRightBorderSum=Integer.MIN_VALUE;
//定义用于求解横跨序列两边最大值的辅助变量
int leftBorderSum=0, rightBorderSum=0;
//定义中间值
int mid = left + (right - left) / 2;
//只剩一个元素
if(left == right) {
return nums[left];
}
//求左右子数组最大值
maxLeftSum = maxValue(nums,left,mid);//-2
maxRightSum = maxValue(nums,mid+1,right);//-1
//横跨序列前半部分和
for(int i = mid; i >= left; i--) {
leftBorderSum += nums[i];
if(leftBorderSum > maxLeftBorderSum) {
maxLeftBorderSum = leftBorderSum;
}
}
//横跨序列的后半部分和
for(int i = mid + 1; i <= right; i++){
rightBorderSum += nums[i];
if(rightBorderSum > maxRightBorderSum) {
maxRightBorderSum = rightBorderSum;
}
}
int BorderSum = maxLeftBorderSum + maxRightBorderSum;
//求三个数中的最大值
if( maxLeftSum > maxRightSum)
return maxLeftSum > BorderSum ? maxLeftSum : BorderSum;
else
return maxRightSum > BorderSum ? maxRightSum : BorderSum;
}
public int maxSubArray(int[] nums) {
return maxValue(nums,0,nums.length-1);
}
-
复杂度分析
A:时间复杂度O(NlogN);
B:空间复杂度O(logN),递归时栈使用的空间;
三、贪心算法
-
思路分析
-
代码实现
public int maxSubArray(int[] nums) {
//定义result和sum
int result = Integer.MIN_VALUE;
int sum = 0;
//遍历数组
for(int i = 0; i < nums.length; i++) {
//更新sum值
sum += nums[i];
//记录result
result = Math.max(sum,result);
//更新sum
if(sum < 0) {
sum = 0;
}
}
return result;
}
-
代码优化版
public int maxSubArray(int[] nums) {
int n = nums.length;
int currSum = nums[0], maxSum = nums[0];
for(int i = 1; i < n; ++i) {
//当前位置的最大和
currSum = Math.max(nums[i], currSum + nums[i]);
//迄今为止的最大和
maxSum = Math.max(maxSum, currSum);
}
return maxSum;
}
-
复杂度分析
A:时间复杂度O(N);
B:空间复杂度O(1),只使用了常数空间;
四、动态规划算法
-
思路分析
-
代码实现
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int maxSum = nums[0];
for(int i = 1; i < n; i++) {
if(nums[i-1] > 0) {
nums[i] += nums[i-1];
}
maxSum = Math.max(nums[i],maxSum);
}
return maxSum;
}
}
-
复杂度分析
A:时间复杂度O(N);
B:空间复杂度O(1),只使用了常数空间;
五、暴力匹配法
-
思路分析
A:求数组所有的子数组的和进行比较,需要两层循环;
B:外循环记录每次开始比较的起始位置;
C:内循环遍历从起始位置开始到最后的所有元素;
-
代码实现
public int maxSubArray(int[] nums) {
int n = nums.length;
int maxSum = Integer.MIN_VALUE;
for(int i = 0; i < n; i++) {
int sum = 0;
for(int j = i; j < n; j++) {
sum += nums[j];
maxSum = Math.max(maxSum,sum);
}
}
return maxSum;
}
-
复杂度分析
A:时间复杂度O(N^2);
B:空间复杂度O(1);