LeetCode 53. Maximum Subarray

问题链接

LeetCode 53. Maximum Subarray

题目解析

求最大子数组。

解题思路

基本题,有多种方法可以得到答案,这里简单讨论一下。

暴力

双重循环遍历子数组起点和终点,再加一重循环计算和,时间复杂度为 \(O(n^3)\),代码就不写了,不可能会用得上的:)

改进

暴力的问题是重复计算,稍微改进一下,将第二层循环去掉,利用变量temp代表从当前数字开始到数组末端的最大子数组,只需要两层循环就够了,时间复杂度为 \(O(n^2)\)

最佳解法

最大子数组问题的最佳解法是 \(O(n)\)

定义两个变量res和temp,其中res为当前最大子数组结果;temp初始值为0,每遍历一个数字num,如果此时temp大于0,这加上num使和更大,否则,令temp=num,表示原来的temp没有对结果做出贡献,抛弃才能使得和更大。当然,这个判断也可以简化成max(temp+num, num)。

深入思考,这其实是DP的思想,不过是简单的DP,而且将dp数组优化成一个变量temp了。可参考DP solution & some thoughts。参考代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res = INT_MIN, temp = 0;
        int len = nums.size();
        for(int i = 0; i < len; i++)
        {
            if(temp > 0) temp += nums[i];
            else temp = nums[i];
            
            if(temp > res) res = temp;
        }
        return res;
    }
};

分治解法

题目要求说试一试分治写法,很有趣。

简单来讲就是每次见数组一分为二,比较(左边的最大子数组之和、右边的最大子数组之和、中间向左右两边扫描的最大子数组之和)三者得到答案。思路比较清晰,写起来也很快。

时间复杂度为:\(O(nlogn)\)。参考代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.empty()) return 0;
        return maxSub(nums, 0, (int)nums.size() - 1);
    }
    int maxSub(vector<int>& nums, int left, int right) {
        if (left >= right) return nums[left];
        
        int mid = (right + left) / 2;
        int lmax = maxSub(nums, left, mid - 1);//Left
        int rmax = maxSub(nums, mid + 1, right);//Right
        
        int mmax = nums[mid], t = mmax;
        for (int i = mid - 1; i >= left; --i) {
            t += nums[i];
            mmax = max(mmax, t);
        }
        t = mmax;
        for (int i = mid + 1; i <= right; ++i) {
            t += nums[i];
            mmax = max(mmax, t);
        }
        return max(mmax, max(lmax, rmax));//三者取最大值
    }
};

LeetCode All in One题解汇总(持续更新中...)

本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.


posted @ 2018-03-16 17:27  AlvinZH  阅读(412)  评论(0编辑  收藏  举报