连续数列(最大子序和)
个人思路
题意
求连续的最大子序和
个人思路代码
O(N)解法
- 遍历整个数组,声明变量ans存储最大值,sum存储当前和
- 如果sum加上后一个元素 比后一个元素还小,则认为后一个元素时无效的并舍弃,并令sum值等于后一个元素的值
- 否则就认为后一个元素是有效的,并加到sum上
- 比较当前的sum值和ans的大小
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size() == 1){
return nums[0];
}
int ans = nums[0];
int sum = nums[0];
for(int i = 1; i < nums.size(); ++i)
{
if(sum + nums[i] <= nums[i])
{
sum = nums[i];
}
else
{
sum += nums[i];
}
if(sum > ans)
{
ans = sum;
}
}
return ans;
}
};
分治法
- 划分:将数组划分为左右子序列,当划分到只剩一个元素时,最大子序和就是他本身(即递归出口)
- 解决:对划分的子序列求当前最大子序和(需要处理最大子序和可能在左子序中,也可能在右子序中,也可能在二者之间的某段)
- 合并:将当前的最大子序和返回
递归体:求左右子序列中的最大子序和,并通过比较得到最大子序和,若不在左右子序列中,则需计算出位于中间的最大子序和
递归出口:当左右指针相等时(即只剩一个元素时),最大子序和就是他本身,返回该元素
思考
Q1:计算最大值时,为什么要用temp进行累加存储
Q2:为什么要从对左子序逆序遍历
A:逆序遍历,所得到的sum1,与sum2进行加和才是中间的最大子序和
class Solution {
public:
int inf = -1 * 0x3fffffff;
int maxSubSum(vector<int>& nums, int left, int right){
//特判
if(nums.size() == 1){
return nums[0];
}
//递归出口
if(left == right){
return nums[left];
}
int mid = (left + right) / 2;
int leftSum = maxSubSum(nums, left, mid);
int rightSum = maxSubSum(nums, mid + 1, right);
//求左子序列的最大字段和
int sum1 = inf;
int tempLeft = 0;
for (int i = mid; i >= left; --i){
tempLeft += nums[i];
if(tempLeft > sum1){
sum1 = tempLeft;
}
}
//求右子序列的最大字段和
int sum2 = inf;
int tempRight = 0;
for(int i = mid + 1; i <= right; ++i){
tempRight += nums[i];
if(tempRight > sum2){
sum2 = tempRight;
}
}
//最大子序和在左子序列中
if((sum1 + sum2 < leftSum) && (rightSum < leftSum)){
return leftSum;
}
//最大子序和在右子序列中
if(sum1 + sum2 < rightSum){
return rightSum;
}
//最大子序和在二者之间
return sum1 + sum2;
}
int maxSubArray(vector<int>& nums) {
int len = nums.size();
return maxSubSum(nums, 0, len - 1);
}
};