标签:public 正数 return problem 难点 最大和 记录 java 思路
时间: 2019-06-30
题目链接:Leetcode
tag: 动态规划
难易程度:简单
题目描述:
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示
1. 1 <= arr.length <= 10^5
2. -100 <= arr[i] <= 100
本题难点
常见解法 | 时间复杂度 | 空间复杂度 |
---|---|---|
暴力搜索 | O(N^2) | O(1) |
分治思想 | O(NlogN) | O(logN) |
动态规划 | O(N) | O(1) |
具体思路
动态规划
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int sum = nums[0];
int former = 0;//用于记录dp[i-1]的值,对于dp[0]而言,其前面的dp[-1]=0
int cur= nums[0];//用于记录dp[i]的值
for(int num: nums){
if(former <= 0){
cur = num;
}
if(former > 0){
cur = former + num;
}//这两句话等同于 cur = Math.max(former,0) + num;
former = cur;
sum = Math.max(sum,cur);
}
return sum;
}
}
复杂度分析:
解题思路
分治法,我们把数组nums以中间位置(mid)分为左(left)右(right)两部分. 那么有,
left = nums[0]...nums[m - 1] 和 right = nums[m + 1]...nums[n-1]
最大子序列和的位置有以下三种情况:
nums[m]
, 跨越左右两部分,这里从中间元素开始,往左求出后缀最大,往右求出前缀最大, 保持连续性。代码
class MaximumSubarrayDivideConquer {
public int maxSubArrayDividConquer(int[] nums) {
if (nums == null || nums.length == 0) return 0;
return helper(nums, 0, nums.length - 1);
}
private int helper(int[] nums, int l, int r) {
if (l > r) return Integer.MIN_VALUE;
int mid = (l + r) >>> 1;
int left = helper(nums, l, mid - 1);
int right = helper(nums, mid + 1, r);
int leftMaxSum = 0;
int sum = 0;
// left surfix maxSum start from index mid - 1 to l
for (int i = mid - 1; i >= l; i--) {
sum += nums[i];
leftMaxSum = Math.max(leftMaxSum, sum);
}
int rightMaxSum = 0;
sum = 0;
// right prefix maxSum start from index mid + 1 to r
for (int i = mid + 1; i <= r; i++) {
sum += nums[i];
rightMaxSum = Math.max(sum, rightMaxSum);
}
// max(left, right, crossSum)
return Math.max(leftMaxSum + rightMaxSum + nums[mid], Math.max(left, right));
}
}
标签:public 正数 return problem 难点 最大和 记录 java 思路
原文地址:https://www.cnblogs.com/ID-Wangqiang/p/13233278.html