【2022 力扣春招季--刷题 PK】5236. 美化数组的最少删除数(中等)

88 阅读2分钟

“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”

一、题目描述

给你一个下标从 0 开始的整数数组 nums ,如果满足下述条件,则认为数组 nums 是一个 美丽数组 :

  • nums.length 为偶数
  • 对所有满足 i % 2 == 0 的下标 i ,nums[i] != nums[i + 1] 均成立

注意,空数组同样认为是美丽数组。

你可以从 nums 中删除任意数量的元素。当你删除一个元素时,被删除元素右侧的所有元素将会向左移动一个单位以填补空缺,而左侧的元素将会保持 不变 。

返回使 nums 变为美丽数组所需删除的 最少 元素数目

 

示例 1:

输入: nums = [1,1,2,3,5]
输出: 1
解释: 可以删除 nums[0] 或 nums[1] ,这样得到的 nums = [1,2,3,5] 是一个美丽数组。可以证明,要想使 nums 变为美丽数组,至少需要删除 1 个元素。

示例 2:

输入: nums = [1,1,2,2,3,3]
输出: 2
解释: 可以删除 nums[0] 和 nums[5] ,这样得到的 nums = [1,2,2,3] 是一个美丽数组。可以证明,要想使 nums 变为美丽数组,至少需要删除 2 个元素。

 

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 105

二、思路分析

这道题要返回使 nums 变为美丽数组所需删除的 最少 元素数目 ,翻译一下也就是,在尽可能少地删除数组元素的前提下,①下标是偶数的元素不能等于其后一个元素;②删除后的数组长度要为偶数。

笔者一看到要删除数组元素,就想到了 JS 中的 splice 方法,并作为思考方向,但其实并不需要真的删除数组,我们要的只是删除数组元素的次数,定义一个变量维护就好了。
那么在不删除数组元素的前提下,怎么实现删除数组元素的效果呢?思路如下:

  • 遍历 nums 数组,第一个元素的下标肯定是偶数,因此判断其是否等于它的后一个元素,不是的话就遍历下一个下标为偶数的元素,是的话就将删除次数 +1 并继续遍历后一个元素(为什么是遍历后一个元素而不是遍历后后一个元素呢?因为这里相当于删除操作,删除了一个元素后,后面的元素就会顶上来,取代被删除元素的位置,此时就要继续判断当前元素是否等于后一个元素)。
  • 遍历完成之后,还需判断删除后的数组的长度是否为偶数,不是的话说明不是美丽数组,要再删除一个元素(删除最后一个元素即可,直接将删除次数 +1);如果是偶数的话就可以返回结果了,此时删除后的数组已经是美丽数组了。

注意1:遍历的区间是 [0, nums.length - 1),因为要判断当前元素是否与其后一个元素相等,当遍历到 nums.length - 1 的位置时,就会发生数组越界。

注意2:为什么在遍历时不用判断当前元素的下标是否为偶数?因为数组是从 0 开始遍历的,我们在遍历时保证当前元素的下标始终为偶数。
那么如何保证呢?一开始下标就为偶数,如果 nums[i] === nums[i + 1] ,下标后移一位,但依然是偶数,相当于元素被删除后多余的空间被后面的元素取代;如果 nums[i] !== nums[i + 1] ,下标自然就后移两位,此时依然为偶数。自始至终,下标始终为偶数,因此也就不需要判断当前元素的下标是否为偶数了。

三、AC 代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var minDeletion = function(nums) {
    let ans = 0;
    let i = 0;
    while (i < nums.length - 1) {
        if (nums[i] === nums[i + 1]) {
            ans++;
            i++;
            continue;
        }
        i += 2;
    }
    if ((nums.length - ans) % 2) {
        ans++;
    }
    return ans;
};