赞
踩
目录
难度 中等
给定一个长度为 n
的环形整数数组 nums
,返回 nums
的非空 子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i]
的下一个元素是 nums[(i + 1) % n]
, nums[i]
的前一个元素是 nums[(i - 1 + n) % n]
。
子数组 最多只能包含固定缓冲区 nums
中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], ..., nums[j]
,不存在 i <= k1, k2 <= j
其中 k1 % n == k2 % n
。
示例 1:
输入:nums = [1,-2,3,-2] 输出:3 解释:从子数组 [3] 得到最大和 3
示例 2:
输入:nums = [5,-3,5] 输出:10 解释:从子数组 [5,5] 得到最大和 5 + 5 = 10
示例 3:
输入:nums = [3,-2,2,-3] 输出:3 解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3
提示:
n == nums.length
1 <= n <= 3 * 10^4
-3 * 10^4 <= nums[i] <= 3 * 10^4
- class Solution {
- public:
- int maxSubarraySumCircular(vector<int>& nums) {
-
- }
- };
类似打家劫舍中把环形问题转换成线性问题的思路:
本题与最大大数组和的区别在于,考虑问题的时候不仅要分析数组内的连续区域,还要考虑数组首尾相连的一部分。结果的可能情况分为以下两种:
其中,对于第一种情况,我们仅需按照最大子数组和的求法就可以得到结果,记为 fmax 。
对于第⼆种情况,可以分析⼀下:
如果数组首尾相连的一部分是最大的数组和,那么数组中间就会空出来⼀部分,因为数组的总和 sum 是不变的,那么中间连续的一部分的和一定是最小的。因此,就可以得出⼀个结论,对于第⼆种情况的最大和,应该等于 sum - gmin ,其中gmin 表示数组内的最小子数组和。
两种情况下的最大值,就是我们要的结果。
但是,由于数组内有可能全部都是负数,第⼀种情况下的结果是数组内的最大值(是个负数),第⼆种情况下的 gmin == sum ,求的得结果就会是 0 。若直接求两者的最大值,就会是 0。但是实际的结果应该是数组内的最大值。对于这种情况,需要特殊判断⼀下。
由于最大子数组和的方法已经讲过,最小子数组和的求解过程,与其求法是一致的。这里用 f 数组表示最大和, g 数组表示最小和。
- class Solution {
- public:
- int maxSubarraySumCircular(vector<int>& nums) {
- int n = nums.size();
- vector<int> f(n), g(n);;
- int fmax = f[0] = g[0] = nums[0], sum = nums[0], gmin = nums[0];
- for(int i = 1; i < n; ++i)
- {
- sum += nums[i];
-
- f[i] = max(nums[i], f[i-1] + nums[i]);
- fmax = max(fmax, f[i]);
-
- g[i] = min(nums[i], g[i-1] + nums[i]);
- gmin = min(gmin, g[i]);
- }
- return sum == gmin ? fmax : max(fmax, sum - gmin);
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。