多多的传送门2:
例如:
输入:5
[1,-4,10,-30,2]
输出:37
解释:多多先选择1,-4,10传送到7位置,使用反转能力到-7,再选择-30到达最远位置-37
思路: 使用前缀和
i 是使用反转的地方,j 就是使用反转后走到的地方。
-preSum[i] + (preSum[j] - preSum[i]) = -2 x preSum[i] + preSum[j]
也就是找两个值(0 <= i < j <= n-1),使得当走到 i 时,preSum[j] 值要取最小或者最大值
这里用两个数组保存 preSum[i~n-1] 的最大和最小值,最后依次遍历,当遍历到 preSum[i] 时,取
preSumMaxPost[i+1] 或 preSumMinPost[i+1] 作为 preSum[j],比较最大值
PS:需要考虑特殊情况,就是一次反转都没用,那就直接 res = max(res, abs(preSum[i+1])); 即可
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
int n = scanner.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
scanner.close();
// 计算最大距离
System.out.println(maxDistance(n, a));
}
public static long maxDistance(int n, int[] a) {
long[] preSum = new long[n + 1];
long res = 0;
// 计算前缀和
for (int i = 0; i < n; i++) {
preSum[i + 1] = preSum[i] + a[i];
}
// 计算后缀最大最小值
long[] preSumMaxPost = new long[n + 1];
long[] preSumMinPost = new long[n + 1];
preSumMaxPost[n] = preSum[n]; // 末尾初始化
preSumMinPost[n] = preSum[n];
for (int i = n - 1; i >= 0; i--) {
preSumMaxPost[i] = Math.max(preSumMaxPost[i + 1], preSum[i]);
preSumMinPost[i] = Math.min(preSumMinPost[i + 1], preSum[i]);
}
// 遍历寻找最大值
for (int i = 0; i < n; i++) {
res = Math.max(res, Math.abs(preSum[i + 1])); // 不反转的情况
res = Math.max(res, Math.abs(-2 * preSum[i] + preSumMaxPost[i + 1]));
res = Math.max(res, Math.abs(-2 * preSum[i] + preSumMinPost[i + 1]));
}
return res;
}
}