[Leetcode] 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.

click to show more practice.

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.


思路一:从前向后。如果前面的和已经小于0了,那么抛弃前面的部分,从当前部分重新计算,因为如果sum{A[i], ... , A[j]} < 0,那么A[i] + ... + A[j] + A[j+1] + ... + A[k] 总是小于 A[j] + A[j+1] + ... + A[k] 的,所以抛弃前面的段。通过这样的做法,我们可以得到很多subarray,实时更新最大值即可。


class Solution {
public:
    int maxSubArray(int A[], int n) {
        int current_sum = A[0];
        int max_sum = A[0];
        for (int i = 1; i < n; ++i) {
            current_sum = current_sum > 0 ? current_sum + A[i] : A[i];
            max_sum = max_sum > current_sum ? max_sum : current_sum;
        }
        return max_sum;
    }
};


总结:复杂度为O(n). 


思路二:Divide and conquer.

        Leetcode上建议了这种做法,实际上复杂度更高,只是为了体现一种思想。我们知道,如果将一个数组劈成两半,那么最大和的子数组可能在左边,在右边,或者是包含pivot的一段数组。将数组持续拆分,直到拆分到只剩下一个元素,这时最大和子数组必然就是这个元素了,可以直接返回。然后利用上面的规律,和拆分后返回的结果,逐步合并,最后得到全局的最大和子数组。整个过程有点像merge sort.


class Solution {
public:
    int max_subarray_helper(const int A[], int lower_bound, int upper_bound) {
        if (lower_bound == upper_bound) return A[lower_bound];
        int mid = (lower_bound + upper_bound) / 2;
        int left_max = max_subarray_helper(A, lower_bound, mid);
        int right_max = max_subarray_helper(A, mid + 1, upper_bound);
        int left_sum = A[mid];
        int left_sum_max = A[mid];
        for (int i = mid - 1; i >= lower_bound; --i) {
            left_sum += A[i];
            left_sum_max = left_sum_max > left_sum ? left_sum_max : left_sum;
        }
        int right_sum = A[mid+1];
        int right_sum_max = A[mid+1];
        for (int i = mid + 2; i <= upper_bound; ++i) {
            right_sum += A[i];
            right_sum_max = right_sum_max > right_sum ? right_sum_max : right_sum;
        }
        int temp_max = left_max > right_max ? left_max : right_max;
        return temp_max > (left_sum_max + right_sum_max) ? temp_max : left_sum_max + right_sum_max;
    }
    
    int maxSubArray(int A[], int n) {
        return max_subarray_helper(A, 0, n - 1);
    }
};


总结:将拆分过程看成一个二叉树,树的root是长度为n的数组,叶子为每一个元素,树的高度为logn. 在merge的过程中,每一层都要对每一个元素遍历一遍,因此每一层的复杂度为O(n). 综上,复杂度为O(nlogn).


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值