题目
题解
前置题是这道Leetcode53-最大子数组和
当数组变成环形的之后,最大子序和有两种可能:
- 在中间,则可以变成最大子序和,即图中case1
- 在两边(例如:[5,-3,5]),即图中case2,这时候最大子序和=数组总和-最小子序和
- 特殊情况:当数组元素全为负数(例如:[-3,-2,-3]),此时最小子序和=所有负数相加(即数组总和),2中结果会变为0,此情况应当选出数组中最大值进行返回
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n=nums.length,sum,max,min;
if(n==1)
return nums[0];
int[] dp_max=new int[n];//最大子序和
int[] dp_min=new int[n];//最小子序和
dp_max[0]=dp_min[0]=sum=max=min=nums[0];
for(int i=1;i<n;i++){
sum+=nums[i];//数组总和
dp_max[i]=Math.max(dp_max[i-1]+nums[i],nums[i]);
dp_min[i]=Math.min(dp_min[i-1]+nums[i],nums[i]);
max=Math.max(max,dp_max[i]);
min=Math.min(min,dp_min[i]);
}
//数组元素全是负数
if(min==sum)
return max;
return Math.max(max,sum-min);
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
如果要用O(1)的空间复杂度实现:将dp_max[],dp_min[]变为整型变量
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int sum=0,max=-30001,min=30001,pre_max=-30001,pre_min=30001;
for(int a:nums){
sum+=a;//数组总和
pre_max=Math.max(pre_max+a,a);//最大子序和
pre_min=Math.min(pre_min+a,a);//最小子序和
max=Math.max(max,pre_max);
min=Math.min(min,pre_min);
}
return min==sum?max:Math.max(max,sum-min);
}
}