方法一:分治法(处理线段树的)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
return findMax(nums, 0, nums.size()-1);
}
// 分治算法求解
// 思路就是把这个问题分成三部分:1、求左边[0, middle-1]这个闭区间部分的max;2、求右边[middle+1, nums.size()-1]这个闭区间部分的max;
// 和3、跨越中间元素部分的max(这部分是从左边跨越的max + 中间元素的值(即nums[middle]) + 从右边跨越的max)。
// 然后比较三个部分,哪个部分是最大值,就是最终的题解。
int findMax(vector<int>& nums, int start, int end)
{
// 判断边界条件
if(start == end) return nums[start];
if(start > end) return INT_MIN;
int left_max, right_max; // 分别定义第一部分的解和第二部分的解
int middle = (start + end) / 2; // 找出这个数组中间元素的位置
int left_sum = 0, right_sum = 0, mid_to_left_max = 0, mid_to_right_max = 0; // 定义从左边跨越的max和从右边跨越的max
// 注意:mid_to_left_max和mid_to_right_max的初始值定义为0就好,因为如果从左跨越和从右跨越都没有比0大的,
// 那这两部分就直接是0就好了,最后和nums.[middle]加起来也还是中间值本身,没有问题。
// 不可以定义为INT_MIN!!!不然很容易就会越界的。
left_max = findMax(nums, start, middle-1); // 第一部分
right_max = findMax(nums, middle+1, end); // 第二部分
for(int i=middle-1; i>=start; i--)
{
// 第三部分 -> 从左边跨越
left_sum += nums[i];
if(mid_to_left_max < left_sum) mid_to_left_max = left_sum;
}
for(int i=middle+1; i<=end; i++)
{
// 第三部分 -> 从右边跨越
right_sum += nums[i];
if(mid_to_right_max < right_sum) mid_to_right_max = right_sum;
}
return (max(max(left_max, right_max), mid_to_left_max + mid_to_right_max + nums[middle]));
}
};
方法二:动态规划
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x: nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};