LeetCode 面试经典 150_Kadane_环形子数组的最大和(110_918_C++_中等)
题目描述:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
输入输出样例:
示例 1:
输入 :nums = [-2,1,-3,4,-1,2,1,-5,4]
输出 :6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入 :nums = [1]
输出:1
示例 3:
输入 :nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
题解:
解题思路:
思路一(动态规划):
0、在解决此问题时需用到一个结论(注意此处均表示子数组 ):
数组和(nums_sum) = 最大和(maxSum) + 最小和(minSum)
maxSum = nums_sum - minSum
因求 最大和 时 必定导致 其他元素 相加最小
通过此结论,可以直接求 最大和 或者 通过最小和来间接的求得最大和
1、在处理此问题时可分情况讨论:
- 情况一 :最大和在数组内部,例 nums = [-1,-2,3,4,-5] ,其中 【3,4】为最大和
- 情况二 :最大和在数组两侧,例 nums = [3 ,-1,-2,-5,4] ,其中 【3,4】为最大和
- 情况三:全为负数,例 nums=[-1,-2,-3,-4,-5],其中【-1】为最大和
若为 情况一 遍历一遍数组只能 求得 最大和 ,和部分最小和 。
若为 情况二 遍历一遍数组只能 求得 最小和 ,和部分最大和 ,需通过maxSum = nums_sum - minSum 求得真实的 最大和 。
若为 情况三 遍历一遍数组只能 求得 最大和 ,且此时最小和为 0
2、复杂度分析:
① 时间复杂度:O(n),其中 n 是输入数组 nums 的长度,只进行了 一次遍历。
② 空间复杂度:O(1)。
代码实现
代码实现(思路一(动态规划)):
cpp
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
// 用来记录当前连续子数组的最大和
int preMaxSum = 0;
// 用来记录找到的最大子数组和
int maxSum = INT_MIN;
// 用来记录当前连续子数组的最小和
int preMinSum = 0;
// 用来记录找到的最小子数组和
int minSum = 0;
// 用来记录所有元素的总和
int nums_sum = 0;
// 遍历输入数组
for(int x : nums) {
// 更新当前最大子数组和,若当前子数组和小于0则从新开始
preMaxSum = max(preMaxSum, 0) + x;
// 更新最大子数组和
maxSum = max(preMaxSum, maxSum);
// 更新当前最小子数组和,若当前子数组和大于0则从新开始
preMinSum = min(preMinSum, 0) + x;
// 更新最小子数组和
minSum = min(preMinSum, minSum);
// 累加元素到总和中
nums_sum += x;
}
// 如果最大子数组和小于0,说明所有元素都是负数,返回最大子数组和
// 否则返回最大值:最大子数组和 和 (总和 - 最小子数组和)
return maxSum < 0 ? maxSum : max(maxSum, nums_sum - minSum);
}
};
以思路一为例进行调试
cpp
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
// 用来记录当前连续子数组的最大和
int preMaxSum = 0;
// 用来记录找到的最大子数组和
int maxSum = INT_MIN;
// 用来记录当前连续子数组的最小和
int preMinSum = 0;
// 用来记录找到的最小子数组和
int minSum = 0;
// 用来记录所有元素的总和
int nums_sum = 0;
// 遍历输入数组
for(int x : nums) {
// 更新当前最大子数组和,若当前子数组和小于0则从新开始
preMaxSum = max(preMaxSum, 0) + x;
// 更新最大子数组和
maxSum = max(preMaxSum, maxSum);
// 更新当前最小子数组和,若当前子数组和大于0则从新开始
preMinSum = min(preMinSum, 0) + x;
// 更新最小子数组和
minSum = min(preMinSum, minSum);
// 累加元素到总和中
nums_sum += x;
}
// 如果最大子数组和小于0,说明所有元素都是负数,返回最大子数组和
// 否则返回最大值:最大子数组和 和 (总和 - 最小子数组和)
return maxSum < 0 ? maxSum : max(maxSum, nums_sum - minSum);
}
};
int main(int argc, char const *argv[])
{
vector<int> nums={-2,1,-3,4,-1,2,1,-5,4};
Solution s;
cout<<s.maxSubarraySumCircular(nums);
return 0;
}
LeetCode 面试经典 150_Kadane_环形子数组的最大和(110_918)原题链接
欢迎大家和我沟通交流(✿◠‿◠)