来源:力扣(LeetCode)
描述:
给你一个整数数组 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*104
- -105 <= nums[i] <= 105
方法:枚举所有可能性
思路
设数组 nums 的长度为 n。原数组的数组值的表达式为 value1 = ∑ i = 0 n − 2 \sum_{i=0}^{n−2} ∑i=0n−2∣nums[i + 1] − nums[i]∣。假设我们选择起点下标为 j,终点下标为 k (j ≤ k) 的子数组进行翻转,下面进行讨论:
- j = k,此时不难发现执行翻转操作后的数组的数组值 value2 = value1。
- j = 0 且 k = n − 1,此时 value2 = value1。
- j = 0 且 k < n − 1,此时 value2 = ∑ i = 0 k − 1 \sum_{i=0}^{k−1} ∑i=0k−1 ∣nums[i + 1] − nums[i]∣ + ∣nums[k + 1] − nums[0]∣ + ∑ i = k + 1 n − 1 \sum_{i=k+1}^{n−1} ∑i=k+1n−1 ∣nums[i + 1] − nums[i]∣。可以得到 value2 = value1 − ∣nums[k + 1] − nums[k]∣ + ∣nums[k + 1] − nums[0]∣。这种情况下 value2 的最大值可以通过遍历 k 获得。
- j > 0 且 k = n − 1。此时 value2 = value1 − ∣nums[j] − nums[j − 1]∣ + ∣nums[n − 1] − nums[j − 1]∣。这种情况下 value2 的最大值可以通过遍历 j 获得。
- j > 0 且 k < n − 1。此时 value2 = value1 − ∣nums[j] − nums[j − 1]∣ − ∣nums[k + 1] − nums[k]∣ + ∣nums[k] − nums[j − 1]∣ + ∣nums[k + 1] − nums[j]∣。令 δ = −∣nums[j] − nums[j − 1]∣ − ∣nums[k + 1] − nums[k]∣ + ∣nums[k] − nums[j − 1]∣ + ∣nums[k + 1] − nums[j]∣,则 value2 = value1 + δ。因为 value1 为定值,为了使 value2 取得最大值,需要求出 δ 的最大值。这种情况下 δ 的最大值可以通过双重遍历 j 和 k 获得,但会带入较大的时间复杂度。为了降低时间复杂度,仍要进行讨论。假设 nums[j − 1], nums[j], nums[k], nums[k + 1] 四个数由小到大排列的值分别为 a, b, c, d,下面进行讨论:
- ∣nums[j] − nums[j − 1]∣ = b − a,∣nums[k + 1] − nums[k]∣ = d − c,则 δ = −(b − a) − (d − c) + nums[k − nums[j − 1] + nums[k + 1] − nums[j] = 2 × (c − b)。
- ∣nums[j] − nums[j − 1]∣ = d − c,∣nums[k + 1] − nums[k]∣= b − a,则 δ = −(d − c) − (b − a − nums[k] + nums[j − 1] − nums[k + 1] + nums[j] = 2 × (c − b)。即同上。
- ∣nums[j] − nums[j − 1]∣ = c − a,∣nums[k + 1] − nums[k]∣= d − b。此时 δ = a + b − c − d + ∣nums[k] − nums[j − 1]∣ + ∣nums[k + 1] − nums[j]∣。可以发现这时 δ 不可能为正数,因为最大的两项已经为负数,后四项为两正两负,无法使 δ 为正数。
- ∣nums[j] − nums[j − 1]∣ = d − a,∣nums[k + 1] − nums[k]∣ = c − b。此时 δ = a + b − c − d + ∣nums[k]− nums[j − 1]∣ + ∣nums[k + 1] − nums[j]∣。同上。
- ∣nums[j] − nums[j − 1]∣ = c − b,∣nums[k + 1] − nums[k]∣ = d − a。同上。
- ∣nums[j] − nums[j − 1]∣ = d − b,∣nums[k + 1] − nums[k]∣ = c − a。同上。
讨论完六种情况后发现只有两种情况下 δ 可能为正。这两种情况下,均是求 2 × (c − b)。即两个相邻数对,当一个数对的较大值小于另一个数对的较小值时,求差值的两倍。我们需要求出这个差值的两倍的最大值。求出 δ 的最大值后,加上 value1 ,即为 value2 的最大值。
最后再求出这五种情况下的最大值即可返回结果。
代码:
class Solution {
public:
int maxValueAfterReverse(vector<int>& nums) {
int value = 0, n = nums.size();
for (int i = 0; i < n - 1; i++) {
value += abs(nums[i] - nums[i + 1]);
}
int mx1 = 0;
for (int i = 1; i < n - 1; i++) {
mx1 = max(mx1, abs(nums[0] - nums[i + 1]) - abs(nums[i] - nums[i + 1]));
mx1 = max(mx1, abs(nums[n - 1] - nums[i - 1]) - abs(nums[i] - nums[i - 1]));
}
int mx2 = INT_MIN, mn2 = INT_MAX;
for (int i = 0; i < n - 1; i++) {
int x = nums[i], y = nums[i + 1];
mx2 = max(mx2, min(x, y));
mn2 = min(mn2, max(x, y));
}
return value + max(mx1, 2 * (mx2 - mn2));
}
};
执行用时:48 ms, 在所有 C++ 提交中击败了96.97%的用户
内存消耗:39.2 MB, 在所有 C++ 提交中击败了89.39%的用户
复杂度分析
时间复杂度:O(n),其中 n 是输入数组 nums 的长度。
空间复杂度:O(1)。仅使用常数空间。
author:LeetCode-Solution