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 转换为锯齿数组所需的最小操作次数。
 
          来源:力扣(LeetCode)
 

二、思路

        一开始没怎么理解题目,感觉好难。后来仔细一想,只需要分奇数、偶数索引两种情况遍历数组就可以用。假定偶数索引对应的元素都大于相邻的元素,则我们只需要遍历所有的偶数索引处的元素,判断它的元素值:如果它的值大于相邻元素,对它进行递减操作;否则不进行任何操作。
        以[9, 6, 1, 6, 2]为例,
        情况一:偶数索引处值大于相邻元素,固定9、1、2是不动的,遍历奇数处元素,i=1时,nums[1]=6,使得6小于两侧的元素9和1,因此将6递减至0,需要进行6次操作;i=3时,将对应的元素值6递减至min(1, 2)-1,即0,也需要进行6次操作;因此情况一需进行12次递减操作
        情况二:奇数索引处元素大于相邻元素,固定6、6不动,遍历偶数处元素,递减它们的值至满足要求。i=0时,将9递减至比6小,即5,需进行4次操作;i=2时,对应元素值1小于相邻元素;i=4时对应元素值2小于相邻元素;因此情况二需进行4次操作。4 < 12,因此函数返回4.。
       代码如下:
 
class Solution:
    def movesToMakeZigzag(self, nums: List[int]) -> int:
        length = len(nums)
        cnt_even = 0      #  用于记录情况一时需要进行的最小操作次数
        cnt_odd = 0       #  用于记录情况二时需要进行的最小操作次数
         # 情况一:偶数位置元素大的情况, 遍历、修改奇数位置的元素
        for i in range(1, length, 2):
            #  根据i处是否是最后一个元素进行分情况讨论
            if i + 1 < length:
                # 判断相邻的两个元素谁更小,我们需要将nums[i]递减到比较小值还要小1
                if nums[i - 1] < nums[i + 1]:
                    if nums[i] >= nums[i-1]:
                        cnt_even += (nums[i] - nums[i - 1] + 1)
                else:
                    if nums[i] >= nums[i+1]:
                         cnt_even += (nums[i] - nums[i + 1] + 1)
            # i处是最后一个元素,因此只有左侧一个相邻元素
            else:
                if nums[i] > nums[i - 1]:
                    cnt_even += (nums[i] - nums[i - 1] + 1)
        # 情况二:奇数位置元素大时,遍历、修改偶数位置元素
        for i in range(0, length, 2):
            if i + 1 < length:
                if i == 0:
                    if nums[i] >= nums[i + 1]:
                        cnt_odd += (nums[i] - nums[i+1] + 1)
                else:
                    if nums[i - 1] < nums[i + 1]:
                        if nums[i] >= nums[i-1]:
                            cnt_odd += (nums[i] - nums[i - 1] + 1)
                    else:
                        if nums[i] >= nums[i+1]:
                            cnt_odd += (nums[i] - nums[i + 1] + 1)
            else:
                if nums[i] >= nums[i - 1]:
                    cnt_odd += (nums[i] - nums[i - 1] + 1)
        # 返回二者的最小值
        return min(cnt_even, cnt_odd)

    乍一看的话,上面的代码确实比较繁琐,是否有更简洁的写法,在题解中看到了刘岳大佬的解法。其实基本思路是完全一样的,参考代码如下:

def movesToMakeZigzag(nums):
    length = len(nums)
    cnt_even = 0
    cnt_odd = 0
    for i in range(0, length):
        # 固定奇数索引处的值,修改偶数处元素
        if i%2==0:
            d1 = nums[i] - nums[i-1] + 1 if i>0 and nums[i]>=nums[i-1] else 0   # 考虑i=0时的情况,此时d1直接为0
            d2 = nums[i] + nums[i+1] + 1 if i<length-1 and nums[i]>=nums[i+1] else 0
            cnt_even += max(d1, d2)
        else:
            d1 = nums[i] - nums[i-1] + 1 if nums[i] >= nums[i-1] else 0    # 此时,i为奇数,前面一定有其他元素
            d2 = nums[i] - nums[i+1] + 1 if i<length-1 and nums[i]>=nums[i+1] else 0
            cnt_odd += max(d1, d2)
    return min(cnt_even, cnt_odd)

 

        本题一定要注意一点:元素值只能减不能加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值