【LeetCode】1144. 递减元素使数组呈锯齿状

给定一个整数数组,通过减少元素值来将其转化为锯齿数组,即奇数或偶数索引的元素大于相邻元素。文章提供了两种贪心算法实现,分别计算奇数和偶数索引元素大的情况,并返回最小操作次数。关键在于处理数组边界条件,如n=1/2的情况。
摘要由CSDN通过智能技术生成

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 <= nums.length <= 1000
1 <= nums[i] <= 1000


算法一:贪心 + 分类讨论

思路

  • 考虑到题目中分为 奇数索引的数字大偶数索引的数字大 两种情况,我分成两种情况,分别计算它们的操作次数,最后返回最小值。

收获

  • 这道题思路很简单,但是我一直没过的点,忽略了 n = 1 / 2 的情况,此时是不需要操作的,否则会出现 数组越界 的情况,直接返回 0 即可。
  • 我的代码太复杂了, 可以参考算法二。

算法情况

  • 时间复杂度:O(n), n 为 nums 的长度;
  • 空间复杂度:O(1)。

在这里插入图片描述

代码

class Solution {
public:
    int movesToMakeZigzag(vector<int>& nums) {
        if(nums.size() < 3) return 0;
        int ans = 0;
        // 奇数序数的数字比较大
        for(int i=0; i<nums.size(); i+=2){
            if(i==0){
                if(nums[i] >= nums[i+1]){
                    ans += nums[i] - (nums[i+1] - 1);
                }
            }
            else if(i==nums.size() - 1){
                if(nums[i] >= nums[i-1]){
                    ans += nums[i] - (nums[i-1] - 1);
                }
            }
            else{
                // 中间数字
                if(nums[i] >= nums[i-1] || nums[i] >= nums[i+1]){
                    ans += nums[i] - (min(nums[i-1], nums[i+1]) - 1);
                }
            }
        }
        // 偶数序数的数字比较大
        int cnt = 0;
        for(int j=1; j<nums.size(); j+=2){
            if(j == nums.size() - 1){
                if(nums[j] >= nums[j-1]){
                    cnt += nums[j] - (nums[j-1] - 1);
                }
            }
            else{
                // 中间数字
                if(nums[j] >= nums[j-1] || nums[j] >= nums[j+1]){
                    cnt += nums[j] - (min(nums[j-1], nums[j+1]) - 1);
                }
            }
        }
        return min(ans, cnt);
    }
};

算法二:贪心 【简洁代码版】

思路

  • 思路和算法一差不多, 但是该算法把数组越界的情况都看作 INT_MAX ,不需要在另外判断,方便了很多;

  • 情况一: 奇数索引的数字大 ,其实就是考虑 nums[0],nums[2] ,… ,(i % 2 == 0)它们需要满足比两侧奇数索引数字都小;

    情况二: 偶数索引的数字大 ,其实就是考虑 nums[1],nums[3] ,… ,(i % 2 == 1)它们需要满足比两侧偶数索引数字都小;

    因此,可以统一考虑, i % 2 == 0 时,就考虑情况一,结果记录在 ans[0] ,当 i % 2 == 1 时,就考虑情况二,结果记录在 ans[1] 。

收获

  • 数组越界的时候,直接看作 INT_MAX

算法情况

  • 时间复杂度:O(n), 其中 n 为 nums 的长度;
  • 空间复杂度:O(C),其中 C 为 2;

在这里插入图片描述

代码

class Solution {
public:
    int movesToMakeZigzag(vector<int>& nums) {
        vector<int> ans(2);
        for(int i=0; i<nums.size(); ++i){
            int left = i ? nums[i-1] : INT_MAX;
            int right = i < nums.size() - 1 ? nums[i+1] : INT_MAX;
            ans[i % 2] +=  max(nums[i] - min(left, right) + 1,0);
        }
        return min(ans[0], ans[1]);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值