原题链接
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
主要思路:
代码:
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int sum = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
sum = nums[i];
max = Math.max(max, sum);
for (int j = i + 1; j < nums.length; j++) {
sum = sum + nums[j];
max = Math.max(max, sum);
}
}
return max;
}
}
复杂度分析:
主要思路:
dp[i]
,表示以下标 i 结尾元素的最大子序列和dp[i]= max{dp[i-1]+a[i],a[i]}
要点:
dp[i]
,表示以下标 i
结尾元素的最大子序列和dp[i]= max{dp[i-1]+a[i],a[i]}
代码:
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int pre = nums[0];//此为dp[i-1]
for (int i = 1; i < nums.length; i++) {
pre = Math.max(pre + nums[i], nums[i]);//递推求dp[i]
max = Math.max(pre, max);//递推过程中,保存最大的dp即可
}
return max;
}
}
复杂度分析:
主要思路:
sum<0
,从新的位置开始重新找主要流程:
代码:
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum+=nums[i];
max=Math.max(sum,max);
if(sum<0){
sum=0;//小于0,则从新位置开始重新搜索
}
}
return max;
}
}
复杂度分析:
主要流程:
要点:
代码:
class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 0) {
return 0;
}
return maxSub(nums, 0, nums.length - 1);
}
//寻找横跨中间点的最大子序列和,一定包含nums[mid]
public int findCrossingMax(int[] nums, int left, int right, int mid) {
int sum = 0;
int leftMax = Integer.MIN_VALUE;
int rightMax = Integer.MIN_VALUE;
//从中间向左端点找最大序列和
for (int i = mid; i >= left; i--) {
sum += nums[i];
leftMax = Math.max(sum, leftMax);
}
//从中间向右端点找最大序列和
sum = 0;
for (int i = mid + 1; i <= right; i++) {
sum += nums[i];
rightMax = Math.max(rightMax, sum);
}
//由于一定包含mid,所以判断右边是否大于0
if (rightMax > 0) {
return leftMax + rightMax;
} else {
return leftMax;
}
}
//递归函数,寻找最大子序列
public int maxSub(int[] nums, int left, int right) {
//边界判断
if (left == right) {
return nums[left];
}
int mid = left + (right - left) / 2;//获取中点
int leftMax = maxSub(nums, left, mid);//左序列区间最大
int rightMax = maxSub(nums, mid + 1, right);//右序列区间最大
int midMax = findCrossingMax(nums, left, right, mid);//横跨序列区间最大
//三者取最大
return Math.max(leftMax, Math.max(rightMax, midMax));
}
}
复杂度分析:
动态规划法、分治法题解参考
贪心法题解参考
编写主要难点在于找到:
如本题的递归形式为,求三者最大的子序列,递归边界为左端点等于右端点
具体还可以参考:如何编写递归程序(分治法)
编写主要难点在于:
本题中定义的状态数组为 以下标 i 结尾的最大子序列和,递推公式为 dp[i]= max{dp[i-1]+a[i],a[i]}