Given an integer array nums
, define the array value as the sum of |nums[i] - nums[i+1]|
for all valid indices i
(where 0 ≤ i < n-1
). Your task is to maximize this array value by reversing exactly one subarray (i.e., you choose a contiguous segment and reverse it in place).
You need to return the maximum possible array value after making at most one such reversal. If you choose not to reverse any subarray, the original array value applies.
Constraints:
2 ≤ nums.length ≤ 10^5
-10^5 ≤ nums[i] ≤ 10^5
The naive approach would be to try reversing every possible subarray and compute the resulting array value, but with O(n^2)
possible subarrays, this is too slow for large arrays.
Instead, we need to analyze how reversing a subarray affects the array value. Reversing a segment only changes the values at the boundaries of the reversed subarray, so we should focus on how these boundaries change the sum of absolute differences. The goal is to find the subarray whose reversal gives the largest increase in array value.
The key insight is that most of the array remains unchanged after a reversal, except for the pairs that straddle the edges of the reversed segment. If we can efficiently compute the best possible gain from any reversal, we can solve the problem in linear time.
We'll break down the solution into clear steps:
|nums[i] - nums[i+1]|
for all i
.
l
to r
only affects the pairs at the edges: (nums[l-1], nums[l])
and (nums[r], nums[r+1])
(if they exist). All other differences remain the same or are just rearranged within the subarray.
|nums[l-1] - nums[r]|
and |nums[l] - nums[r+1]|
.
l
and r
at the boundaries (i.e., reversing from the start or to the end).
max(min(nums[i], nums[i+1]))
and min(max(nums[i], nums[i+1]))
to find the best possible gain.
This approach ensures we only traverse the array a few times, achieving O(n)
time complexity.
Let's consider the example nums = [2, 3, 1, 5, 4]
.
Brute-force approach: Trying all possible subarrays to reverse would require O(n^2)
time, as each reversal takes O(n)
and there are O(n^2)
possible subarrays.
Optimized approach: By focusing on the effect of reversing on the boundary pairs, we can compute the maximal gain in O(n)
time and O(1)
extra space, aside from the input and some variables for tracking min/max values.
The key insight is that reversing a subarray only affects the edges of the reversed segment. By efficiently computing the potential gain for all possible reversals, we can solve the problem in linear time. This approach avoids brute-force and leverages mathematical reasoning to optimize the solution. The elegance lies in reducing a seemingly complex problem to simple boundary analysis.
class Solution:
def maxValueAfterReverse(self, nums):
n = len(nums)
total = 0
min_max = float('inf')
max_min = float('-inf')
for i in range(n - 1):
a, b = nums[i], nums[i + 1]
total += abs(a - b)
min_max = min(min_max, max(a, b))
max_min = max(max_min, min(a, b))
gain = 0
# Try reversing from the start to i
for i in range(1, n - 1):
gain = max(gain, abs(nums[0] - nums[i + 1]) - abs(nums[i] - nums[i + 1]))
# Try reversing from i to end
for i in range(n - 1):
gain = max(gain, abs(nums[-1] - nums[i]) - abs(nums[i] - nums[i + 1]))
# Try reversing in the middle
gain = max(gain, 2 * (max_min - min_max))
return total + gain
class Solution {
public:
int maxValueAfterReverse(vector<int>& nums) {
int n = nums.size();
int total = 0;
int min_max = INT_MAX, max_min = INT_MIN;
for (int i = 0; i < n - 1; ++i) {
int a = nums[i], b = nums[i + 1];
total += abs(a - b);
min_max = min(min_max, max(a, b));
max_min = max(max_min, min(a, b));
}
int gain = 0;
for (int i = 1; i < n - 1; ++i) {
gain = max(gain, abs(nums[0] - nums[i + 1]) - abs(nums[i] - nums[i + 1]));
}
for (int i = 0; i < n - 1; ++i) {
gain = max(gain, abs(nums[n - 1] - nums[i]) - abs(nums[i] - nums[i + 1]));
}
gain = max(gain, 2 * (max_min - min_max));
return total + gain;
}
};
class Solution {
public int maxValueAfterReverse(int[] nums) {
int n = nums.length;
int total = 0;
int minMax = Integer.MAX_VALUE, maxMin = Integer.MIN_VALUE;
for (int i = 0; i < n - 1; ++i) {
int a = nums[i], b = nums[i + 1];
total += Math.abs(a - b);
minMax = Math.min(minMax, Math.max(a, b));
maxMin = Math.max(maxMin, Math.min(a, b));
}
int gain = 0;
for (int i = 1; i < n - 1; ++i) {
gain = Math.max(gain, Math.abs(nums[0] - nums[i + 1]) - Math.abs(nums[i] - nums[i + 1]));
}
for (int i = 0; i < n - 1; ++i) {
gain = Math.max(gain, Math.abs(nums[n - 1] - nums[i]) - Math.abs(nums[i] - nums[i + 1]));
}
gain = Math.max(gain, 2 * (maxMin - minMax));
return total + gain;
}
}
var maxValueAfterReverse = function(nums) {
const n = nums.length;
let total = 0;
let minMax = Infinity, maxMin = -Infinity;
for (let i = 0; i < n - 1; ++i) {
let a = nums[i], b = nums[i + 1];
total += Math.abs(a - b);
minMax = Math.min(minMax, Math.max(a, b));
maxMin = Math.max(maxMin, Math.min(a, b));
}
let gain = 0;
for (let i = 1; i < n - 1; ++i) {
gain = Math.max(gain, Math.abs(nums[0] - nums[i + 1]) - Math.abs(nums[i] - nums[i + 1]));
}
for (let i = 0; i < n - 1; ++i) {
gain = Math.max(gain, Math.abs(nums[n - 1] - nums[i]) - Math.abs(nums[i] - nums[i + 1]));
}
gain = Math.max(gain, 2 * (maxMin - minMax));
return total + gain;
};