Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
,
the contiguous subarray [4,−1,2,1]
has the largest sum = 6
.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
一种动态规划的例子。和分治法相同,当问题规模比较大不容易解决时,我们试图减小问题规模来解决这些问题。分治法将一个大问题分解成几个规模小的小问题,每个小问题的解相互独立,然后将这些小问题的解合并成原问题的解。由于小问题和原问题的性质相同,可以用递归法
这里用分治法反而比较麻烦。可以用数学归纳法的思想将问题规模为n的问题化为问题规模为n-1 的问题然后推导规模增加了一之后问题的解有什么变化(即求其递推公式)。
数组元素增加一之后最大的subArray sum 有可能有两种情况。第一不变,第二有变化,那肯定新添加进的元素包含在subArray中,那我们就保存两个量一个是最大的subArray sum 一个是以最后一个元素为结尾的子列的最大subArray sum值。即后面的max 和maxend
加进一个新元素之后先更新一下maxend,更新方法是看一下前面的maxend是否大于0,如果大于0加上去,如果小于0的话加上去反而更小。然后就可以比较一下新的maxend 和之前的max哪个大,更新一下max就行。。
class Solution {
public:
int maxSubArray(int A[], int n) {
int max=A[0];
int maxend=A[0];
for(int i=1;i<n;i++)
{
if(A[i]+maxend<A[i])maxend=A[i];
else maxend=A[i]+maxend;
if(maxend>max)max=maxend;
}
return max;
}
};
还有其他的方法,为了保持完整性也贴在下面,以下为转载(repost):
greedy:
class Solution {
public:
int maxSubArray(int A[], int n) {
int sum = 0, min = 0, res = A[0];
for(int i = 0; i < n; i++) {
sum += A[i];
if(sum - min > res) res = sum - min;
if(sum < min) min = sum;
}
return res;
}
};
The idea is to find the largest difference between the sums when you summing up the array from left to right. The largest difference corresponds to the sub-array with largest sum. I worked it out independently although It is very close to lucastan's solution https://oj.leetcode.com/discuss/11288/simple-o-n-c-solution-no-dp-no-divide-and-conquer
divide and conquer:
struct val {
int l, m, r, s;
val(int l, int m, int r, int s):l(l), m(m), r(r), s(s){}
};
class Solution {
public:
val dac(int A[], int n) {
if(n == 1) return val(A[0], A[0], A[0], A[0]);
val v1 = dac(A, n / 2), v2 = dac(A + n / 2, n - n / 2);
int l, m, r, s;
l = max(v1.l, v1.s + v2.l);
m = max(v1.r + v2.l, max(v1.m, v2.m));
r = max(v2.r, v1.r + v2.s);
s = v1.s + v2.s;
return val(l, m, r, s);
}
int maxSubArray(int A[], int n) {
val v = dac(A, n);
return v.m;
}
};
the idea is: for each sub array we calculate 4 values in O(1) time based on the return values of its two halves. The meaning of the values:
- l: the sum of the sub array with largest sum starting from the first element
- m: the sum of the sub array with largest sum
- r: the sum of the sub array with largest sum ending at the last element
- s: the sum of the whole array