题目
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.
我的想法
第一个想到的方法是sliding window,但后来觉得不太对。改用dp,用一个二维数组来存所有的start-end的结果,忽略了长数据,导致内存超了
class Solution {
public int maxSubArray(int[] nums) {
int[][] dp = new int[nums.length][nums.length];
int len = 0;
int max = Integer.MIN_VALUE;
while(len < nums.length) {
for(int i = 0; i + len < nums.length; i++) {
int start = i;
int end = i + len;
if(start == end) {
dp[start][end] = nums[start];
} else {
dp[start][end] = dp[start][end - 1] + nums[end];
}
if(dp[start][end] > max) {
max = dp[start][end];
}
}
len++;
}
return max;
}
}
解答
leetcode solution: DP
别人的dp。。。
以i结尾的子串的最大值dp[i]等于A[i]+dp[i-1],只有dp[i-1]>0加上才会使当前值更大,因此如果dp[i-1]<0就不加
class Solution {
public int maxSubArray(int[] A) {
int n = A.length;
int[] dp = new int[n];//dp[i] means the maximum subarray ending with A[i];
dp[0] = A[0];
int max = dp[0];
for(int i = 1; i < n; i++){
dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
max = Math.max(max, dp[i]);
}
return max;
}
}
jiuzhang solution 1: Greedy
加上一个负数只可能越来越小,如果当前区间的sum<0,不管后面一个数是多少,加上当前值都会变小,因此可以直接把当前区间置0
class Solution {
public int maxSubArray(int[] A) {
int max = Integer.MIN_VALUE;
int sum = 0;
for(int i = 0; i < A.length; i++) {
sum += A[i];
max = Math.max(max, sum);
sum = Math.max(sum, 0);
}
return max;
}
}
leetcode solution2: divide and conquer
public class Solution {//divdie and conquer
public int maxSubArray(int[] nums) {
return Subarray(nums, 0 ,nums.length -1 );
}
public int Subarray(int[] A,int left, int right){
if(left == right){return A[left];}
int mid = left + (right - left) / 2;
int leftSum = Subarray(A,left,mid);// left part
int rightSum = Subarray(A,mid+1,right);//right part
int crossSum = crossSubarray(A,left,right);// cross part
if(leftSum >= rightSum && leftSum >= crossSum){// left part is max
return leftSum;
}
if(rightSum >= leftSum && rightSum >= crossSum){// right part is max
return rightSum;
}
return crossSum; // cross part is max
}
//左右结合在一起的最大值。从中间向两端扩散
public int crossSubarray(int[] A,int left,int right){
int leftSum = Integer.MIN_VALUE;
int rightSum = Integer.MIN_VALUE;
int sum = 0;
int mid = left + (right - left) / 2;
for(int i = mid; i >= left ; i--){
sum = sum + A[i];
if(leftSum < sum){
leftSum = sum;
}
}
sum = 0;
for(int j = mid + 1; j <= right; j++){
sum = sum + A[j];
if(rightSum < sum){
rightSum = sum;
}
}
return leftSum + rightSum;
}
}