leetcode 1144. 递减元素使数组呈锯齿状

题意

给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的值减少 1。

如果符合下列情况之一,则数组 A 就是 锯齿数组:

每个偶数索引对应的元素都大于相邻的元素,即 A[0] > A[1] < A[2] > A[3] < A[4] > …
或者,每个奇数索引对应的元素都大于相邻的元素,即 A[0] < A[1] > A[2] < A[3] > A[4] < …
返回将数组 nums 转换为锯齿数组所需的最小操作次数。

示例 1:

输入:nums = [1,2,3]
输出:2
解释:我们可以把 2 递减到 0,或把 3 递减到 1。
示例 2:

输入:nums = [9,6,1,6,2]
输出:4

解析

  1. 这道题目是前不久的一道leetcode周赛题目,虽然是第一题,但是难度归为了medium。题目其实并不算难,但是但是花费了我很多时间。差点没做出来,有点尴尬。要完成这道题目需要注意的一点是要达到锯齿的形状我们只能将数据减小。那只要捋清思路,我们就可以发现,其实最后只会归为两种情况,一种是将奇数位改为波峰,另一种是将偶数位改为波峰。我当时就是在这里弄晕了,总是担心会发生溢出,最后浪费了很多时间。

  2. 那到这里整理下思路,我们最后的目标是比较下前面两种情况的结果,选出最小值。考虑到边界问题,我们只需要在if条件中加以判断即可。哎,这么一说完就敢更感觉很简单了,真不明白当时为什么花那么久都不清楚。

解答

ac代码如下:

class Solution {
 public:
int movesToMakeZigzag(vector<int>& nums) {
    vector<int> copy=nums;
    int ret1=0,ret2=0;
    for(int i=0;i<copy.size();i++){
        if(i%2==1){ //奇数下标位于波峰
            if(i>0 && copy[i]<=copy[i-1]){
                ret1=ret1+copy[i-1]-copy[i]+1;
                copy[i-1]=copy[i]-1;
            }
            if((i+1)<copy.size() && copy[i]<=copy[i+1]){ //可以把边界也放在循环中考虑
                ret1=ret1+copy[i+1]-copy[i]+1;
                copy[i+1]=copy[i]-1;
            }
        }
    }

    for(int i=0;i<nums.size();i++){
        if(i%2==0){
           if((i+1)<nums.size() &&nums[i]<=nums[i+1]){ //往前一个
               ret2=ret2+nums[i+1]-nums[i]+1;
               nums[i+1]=nums[i]-1;
           }
           if(i>0 && nums[i]<=nums[i-1]){//往后一个
               ret2=ret2+nums[i-1]-nums[i]+1;
               nums[i-1]=nums[i]-1;
           }

        }
    }
    return min(ret1,ret2);
}
};

这里再多说一句,这个代码可以进一步优化,因为两种情况都比较类似,所以我们可以编写一个辅助函数,通过传入一个数组的副本来进行计算。根据是否为奇数选取不同的情况。
最后贴一个通过图:

answer