加载中...
1330-翻转子数组得到最大的数组值(Reverse Subarray To Maximize Array Value)
发表于:2021-12-03 | 分类: 困难
字数统计: 1.2k | 阅读时长: 5分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/reverse-subarray-to-maximize-array-value

英文原文

You are given an integer array nums. The value of this array is defined as the sum of |nums[i] - nums[i + 1]| for all 0 <= i < nums.length - 1.

You are allowed to select any subarray of the given array and reverse it. You can perform this operation only once.

Find maximum possible value of the final array.

 

Example 1:

Input: nums = [2,3,1,5,4]
Output: 10
Explanation: By reversing the subarray [3,1,5] the array becomes [2,5,1,3,4] whose value is 10.

Example 2:

Input: nums = [2,4,9,24,2,1,10]
Output: 68

 

Constraints:

  • 1 <= nums.length <= 3 * 104
  • -105 <= nums[i] <= 105

中文题目

给你一个整数数组 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

通过代码

高赞题解

解题思路

思路参考:@wnjxyk

拿到题目先做一些处理,发现一个简单的性质:

我们假设反转[l,r]:
原数组 … a[l - 1] ,a[l] , … , a[r] , a[r + 1] …
反转后 … a[l - 1] , a[r] , … , a[l] , a[r + 1]…
通过计算发现发生改变的数值仅仅是两个端点

$减少的值 = abs(a[l] - a[l - 1]) + abs(a[r] - a[r + 1]);$
$增加的值 = abs(a[l - 1] - a[r]) + abs(a[l] - a[r + 1]);$
$变化的值 = abs(a[l - 1] - a[r]) + abs(a[l] - a[r + 1]) - (abs(a[l] - a[l - 1]) + abs(a[r] - a[r + 1]));$

说来惭愧比赛的时候我也就处理到这里了。
现在有一个很明显的$O(n^2)$的做法:暴力枚举区间
但看见数据范围的时候心里就一凉,$3 * 10^4$,O($n ^ 2$)是绝对过不去的。

其实我们可以深度挖掘一下这个式子,减少得值已经是单点的值了,不用管他。
我们再观察一下增加的值,这不就是曼哈顿距离嘛。。。

曼哈顿距离有一个暴力开绝对值的方法就是枚举四种情况,然后取max就可以了
$增加的值 = abs(a[l - 1] - a[r]) + abs(a[l] - a[r + 1])$ =
$max{$
$a[l - 1] + a[l] - (a[r] + a[r+1]) ,$
$a[l - 1] - a[l] - (a[r] - a[r + 1]),$
$-a[l - 1] + a[l] - (-a[r] + a[r + 1]),$
$-a[l - 1] - a[l] - (-a[r] - a[r + 1])$
$}$
最后把变化的值计算出来
$变化的值 =$
$max{$
$a[l - 1] + a[l] - abs(a[l] - a[l - 1]) - (a[r] + a[r + 1] + abs(a[r] - a[r + 1])),$
$a[l - 1] - a[l] - abs(a[l] - a[l - 1]) - (a[r] - a[r + 1] + abs(a[r] - a[r + 1])),$
$-a[l - 1] + a[l] - abs(a[l] - a[l - 1]) - (-a[r] + a[r + 1] + abs(a[r] - a[r + 1])),$
$-a[l - 1] - a[l] - abs(a[l] - a[l - 1]) - (-a[r] - a[r + 1] + abs(a[r] - a[r + 1]))$
$}$
这样我们就得到了由单点决定的变化的值

算法

(贪心) O(n)

我们先把不用反转区间的值算出来,记为res,

然后分情况讨论计算出减号左边的数减号右边的数,

分别求最大值和最小值,用最大值 - 最小值就是最大变化数

最后最大变化数 + res相加就是本题的答案

ps:可以通过单独处理边界来减少写代码的难度

代码

class Solution {
public:
    int get_max(vector<int> &v)
    {
        int res = INT_MIN;
        for(auto x : v)
            res = max(res,x);
        
        return res;
    }
    int get_min(vector<int> &v)
    {
        int res = INT_MAX;
        for(auto x : v)
            res = min(res,x);
        
        return res;
    }
    int maxValueAfterReverse(vector<int>& nums) {
        int res = 0;
        int n = nums.size();
        
        for(int i=0;i<n-1;i++)
            res += abs(nums[i] - nums[i + 1]);
        
        int maxv = 0;

        for(int i=0;i<n;i++)
        {
            if(i != n - 1)
                maxv = max(maxv,abs(nums[0] - nums[i + 1]) - 
                                abs(nums[i] - nums[i + 1])); // 左端点为0右端点为i
            if(i != 0)
                maxv = max(maxv,abs(nums[n - 1] - nums[i - 1]) -
                                abs(nums[i] - nums[i - 1])); // 右端点为n-1,左端点为i
        }

        int mx[4] = {1,1,-1,-1};
        int my[4] = {1,-1,1,-1};
        
        for(int i=0;i<4;i++) // 枚举四种情况
        {
            vector<int> v1,v2;
            for(int j=0;j<n-1;j++)
            {
                int a = mx[i] * nums[j];
                int b = my[i] * nums[j + 1];
                int cur = abs(nums[j] - nums[j + 1]);
                v1.push_back(a + b - cur);
                v2.push_back(a + b + cur);
            }
            int a = get_max(v1);
            int b = get_min(v2);
            maxv = max(maxv,a - b);
        }

        return res + maxv;
    }
};

统计信息

通过次数 提交次数 AC比率
1218 3187 38.2%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
1302-层数最深叶子节点的和(Deepest Leaves Sum)
下一篇:
1331-数组序号转换(Rank Transform of an Array)
本文目录
本文目录