import java.util.*;
/**
* NC302 环形数组的连续子数组最大和
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型ArrayList
* @return int整型
*/
public int maxSubarraySumCircular (ArrayList<Integer> nums) {
// return solution1(nums);
return solution2(nums);
// return solution3(nums);
}
/**
* 动态规划 + 前缀和: OOM
*
* dp[i][j]表示从第i个数到第j个数的子数组的和
*
* dp[i][j] = pre[j] - pre[i-1] , 1<=i<=n i<=j<=n
*
* @param nums
* @return
*/
private int solution1(ArrayList<Integer> nums){
int n = nums.size();
// 前缀和
int[] pre = new int[n+1];
for(int i=1; i<=n; i++){
pre[i] = pre[i-1] + nums.get(i-1);
}
int sum = pre[n];
int max = Integer.MIN_VALUE;
int[][] dp = new int[n+1][n+1];
// for(int i=1; i<=n; i++){
// for(int j=1; j<=n; j++){
// if(i <= j){
// dp[i][j] = pre[j] - pre[i-1];
// }else{
// dp[i][j] = sum + (pre[j] - pre[i-1]);
// }
// max = Math.max(max, dp[i][j]);
// }
// }
for(int i=1; i<=n; i++){
for(int j=i; j<=n; j++){
dp[i][j] = pre[j] - pre[i-1];
if(i==1 && j==n){
max = Math.max(max, dp[i][j]);
}else{
max = Math.max(max, Math.max(dp[i][j],sum-dp[i][j]));
}
}
}
return max;
}
/**
* 动态规划 + 前缀和
*
* dp[i]表示以数组中第i个数为结尾的连续子数组的最大和
*
* // 情形1 不考虑环形 结果为 中间某一连续部分
* dp[i] = Math.max(dp[i-1],0) + nums.get(i-1) , 1<=i<=n
* max = Math.max(max, dp[i])
*
* // 情形2 考虑环形 结果为 前面最大连续部分 + 后面固定连续部分
* max = Math.max(max, leftMax[i]+right[i])
*
* @param nums
* @return
*/
private int solution2(ArrayList<Integer> nums){
int n = nums.size();
// 前缀和
int[] pre = new int[n+1];
for(int i=1; i<=n; i++){
pre[i] = pre[i-1] + nums.get(i-1);
}
int[] dp = new int[n+1];
int max = Integer.MIN_VALUE;
int sum = pre[n];
int[] leftMax = new int[n+1];
int[] right = new int[n+1];
for(int i=1; i<=n; i++){
// 情形1 不考虑环形 结果为 中间某一连续部分
// if(dp[i-1] > 0){
// dp[i] = dp[i-1] + nums.get(i-1);
// }else{
// dp[i] = nums.get(i-1);
// }
dp[i] = Math.max(dp[i-1],0) + nums.get(i-1);
max = Math.max(max, dp[i]);
// 情形2 考虑环形 结果为 前面最大连续部分 + 后面固定连续部分
leftMax[i] = Math.max(leftMax[i-1], pre[i-1]);
right[i] = sum - pre[i-1];
max = Math.max(max, leftMax[i]+right[i]);
}
return max;
}
/**
* 动态规划: 空间优化
*
* preMax = Math.max(preMax,0) + nums.get(i-1)
* preMin = Math.min(preMin,0) + nums.get(i-1)
*
* max = Math.max(max, preMax)
* min = Math.min(min, preMin)
*
* @param nums
* @return
*/
private int solution3(ArrayList<Integer> nums){
int n = nums.size();
int sum = 0;
for(int i=1; i<=n; i++){
sum += nums.get(i-1);
}
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i=1,preMin=0,preMax=0; i<=n; i++){
// 情形1 不考虑环形 结果为 中间某一连续部分最大和 max
preMax = Math.max(preMax,0) + nums.get(i-1);
// 情形2 考虑环形 结果为 sum-中间某一连续部分最小和 sum-min
preMin = Math.min(preMin,0) + nums.get(i-1);
max = Math.max(max, preMax);
min = Math.min(min, preMin);
}
// 特殊情况 全为负数
if(max < 0){
return max;
}
return Math.max(max, sum-min);
}
}