难度困难
给你一个整数数组 nums
。「数组值」定义为所有满足 0 <= i < nums.length-1
的 |nums[i]-nums[i+1]|
的和。
你可以选择给定数组的任意子数组,并将该子数组翻转。但你只能执行这个操作 一次 。
请你找到可行的最大 数组值 。
示例 1:
输入:nums = [2,3,1,5,4]
输出:10
解释:通过翻转子数组 [3,1,5] ,数组变成 [2,5,1,3,4] ,数组值为 10 。
示例 2:
输入:nums = [2,4,9,24,2,1,10]
输出:68
提示:
1 <= nums.length <= 3*10^4
-10^5 <= nums[i] <= 10^5
# 数学
对于
- 可以发现,只会影响两边的值,而不会影响局部的值
可以得出:
- 只需要求出 的最大值即可。
可以暴力枚举 求出最大值,但是需要 的时间复杂度,如何优化呢?
class Solution { public int maxValueAfterReverse(int[] nums) { int n = nums.length; int origin = 0; for (int i = 1; i < n; i++) { origin += Math.abs(nums[i] - nums[i - 1]);}
int ans = origin; for (int i = 0; i < n; i++) { int r = i == n - 1 ? 0 : Math.abs(nums[i + 1] - nums[i]); for (int j = 0; j < i; j++) { int l = j == 0 ? 0 : Math.abs(nums[j] - nums[j - 1]);//swap
int cl = j == 0 ? 0 : Math.abs(nums[i] - nums[j - 1]); int cr = i == n - 1 ? 0 : Math.abs(nums[i + 1] - nums[j]); ans = Math.max(ans, origin - (r + l) + (cl + cr));}
}
return ans;}
}
绝对值与最大值的关系:
加法对最大值的分配率:
$d =(|x-a| + |y - b|) - |b-a|-|y-x| $
求解: 的最大值,我们可以在枚举 的过程中并保存 的最大值即可
注意:还需要单独考虑边界
class Solution { | |
public int maxValueAfterReverse(int[] nums) { | |
int n = nums.length; | |
int mx1 = Integer.MIN_VALUE / 2, mx2 = Integer.MIN_VALUE / 2, mx3 = Integer.MIN_VALUE / 2, mx4 = Integer.MIN_VALUE / 2; | |
int ans = 0; | |
int ds = 0; | |
// 边界 | |
for (int i = 0; i < n - 1; i++) { | |
int y = nums[i + 1], x = nums[i]; | |
int dxy = Math.abs(x - y); | |
ds += dxy; | |
// 左边界 | |
ans = Math.max(ans, Math.abs(nums[0] - y) - dxy); | |
// 右边界 | |
ans = Math.max(ans, Math.abs(nums[n - 1] - x) - dxy); | |
// 中间 4 种情况 | |
ans = Math.max(ans, | |
Math.max( | |
Math.max(y + x + mx1, -y + x + mx2), | |
Math.max(y - x + mx3, -y - x + mx4) | |
) - dxy); | |
mx1 = Math.max(mx1, -y - x - dxy); | |
mx2 = Math.max(mx2, y - x - dxy); | |
mx3 = Math.max(mx3, -y + x - dxy); | |
mx4 = Math.max(mx4, y + x - dxy); | |
} | |
return ans + ds; | |
} | |
} |
# 数学 + 分类讨论
参考:不会化简?请看这
(1)
(2)
(3)
(4)
$d =(|x-a| + |y - b|) - |b-a|-|y-x| $
对于 之间大小关系一共有 ,共 种情况。
可以从这 个数选出任意 个数作为最小值,一共有 $C_4^2 = 6 $ 种情况
由于对称性,可以分类讨论 种情况。
①
-
-
由对称性,
②
-
-
由对称性,
当 时,,只翻转一个子数组的情况。
可以不用考虑
②
-
-
由对称性,
从上述可以得出,只有情况 ① 才会使得数组值增大。
即:
class Solution { | |
public int maxValueAfterReverse(int[] nums) { | |
int n = nums.length; | |
int mx = Integer.MIN_VALUE, mn = Integer.MAX_VALUE; | |
int ans = 0; | |
int ds = 0; | |
// 边界 | |
for (int i = 0; i < n - 1; i++) { | |
int y = nums[i + 1], x = nums[i]; | |
int dxy = Math.abs(x - y); | |
ds += dxy; | |
// 左边界 | |
ans = Math.max(ans, Math.abs(nums[0] - y) - dxy); | |
// 右边界 | |
ans = Math.max(ans, Math.abs(nums[n - 1] - x) - dxy); | |
// 维护 min (x, y) 的最大值 mx | |
mx = Math.max(mx, Math.min(x, y)); | |
// 维护 max (a, b) 的最小值 mn | |
mn = Math.min(mn, Math.max(x, y)); | |
} | |
return Math.max(ans, 2 * (mx - mn)) + ds; | |
} | |
} |