问题链接
题目解析
求最大子数组。
解题思路
基本题,有多种方法可以得到答案,这里简单讨论一下。
暴力
双重循环遍历子数组起点和终点,再加一重循环计算和,时间复杂度为 \\(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和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.