题目链接:Maximum Subarray

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.

More practice:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

这道题的要求是找到数组中和最大的连续子数组。拓展练习,尝试分治去解决问题哦,更有趣呦。

  1. 动态规划

非常常见的动态规划问题,也是入门级简单的动态规划。用maxl[i]数组表示包含i元素的子数组的最大和,则动态规划的递推公式为:maxl[i+1] = max(maxl[i]+A[i], A[i+1]),即最大值一定是数组当前元素以及数组当前元素和前一结果之和的最大值。接下来整个问题的最大值就是maxl数组中的最大值。

然而由于masl[i]只是用到了前一结果,因此在实际处理的时候,可以用cur变量维护包含当前元素的最大值,用res维护最后最大值。则cur = max(cur+A[i], A[i]),res = max(res, cur)。

时间复杂度:O(n)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution
{
public:
    int maxSubArray(int A[], int n)
    {
        int res = A[0], cur = A[0];
        for(int i = 1; i < n; ++ i)
        {
            cur = max(cur + A[i], A[i]);
            res = max(res, cur);
        }
        return res;
    }
};
  1. 分而治之

问题解决了,可是发现了下面的拓展,即分治解决。提到分治,思路来了,当前的最大值等于左侧最大值和右侧最大值中较大的。可是,有一点点问题,这个最大值还有可能是横跨左右两侧的啊。。。

于是,在处理两侧的子问题的时候,需要同时分别计算包含最左端元素的最大值(lres)和包含最右端元素的最大值(rres)。这样,当前的最大值就为“左侧最大值(res1)”、“右侧最大值(res2)”、“左侧含最右端元素的最大值(rres1)及右侧包含最左端元素的最大值(lres2)之和”三者的最大值。

而由于lres可分为只在左侧和也包含右侧两种情况:

  • 左侧含最左端元素的最大值(lres1)
  • 左侧元素之和加右侧含最左端元素的最大值(all1+lres2)

含最右端元素的最大值同理,即lres = max(lres1, all1 + lres2)和rres = max(rres2, all2 + rres1)。

问题得以解决。至于时间复杂度,个人认为,是n/2 + n/4 + n/8 + … = O(n)。

时间复杂度:O(n)

空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution
{
public:
    int maxSubArray(int A[], int n)
    {
        int res, lres, rres, all;
        maxSubArray(A, 0, n - 1, res, lres, rres, all);
        return res;
    }
private:
    void maxSubArray(int A[], int l, int r, 
                     int &res, int &lres, int &rres, int &all)
    {
        if(l == r)
        {
            res = lres = rres = all = A[l];
            return;
        }

        int m = (l + r) / 2;
        int res1, lres1, rres1, all1, res2, lres2, rres2, all2;

        maxSubArray(A, l, m, res1, lres1, rres1, all1);
        maxSubArray(A, m + 1, r, res2, lres2, rres2, all2);

        res = max(max(res1, res2), rres1 + lres2);
        lres = max(lres1, all1 + lres2);
        rres = max(rres2, all2 + rres1);
        all = all1 + all2;
    }
};