当前位置: 首页 > news >正文

力扣每日打卡 3396. 使数组元素互不相同所需的最少操作次数(简单)

力扣 3396. 使数组元素互不相同所需的最少操作次数 简单

  • 前言
  • 一、题目内容
  • 二、解题方法
    • 1. 暴力解法
    • 2. 哈希函数
    • 3. 官方题解
      • 3.1 方法一:模拟
      • 3.2 方法二:倒序遍历


前言

这是刷算法题的第九天,用到的语言是JS
题目:力扣 3396. 使数组元素互不相同所需的最少操作次数(简单)


一、题目内容

给你一个整数数组 nums,你需要确保数组中的元素 互不相同 。为此,你可以执行以下操作任意次:

从数组的开头移除 3 个元素。如果数组中元素少于 3 个,则移除所有剩余元素。
注意:空数组也视作为数组元素互不相同。返回使数组元素互不相同所需的 最少操作次数 。

示例 1:
输入: nums = [1,2,3,4,2,3,3,5,7]
输出: 2
解释:
第一次操作:移除前 3 个元素,数组变为 [4, 2, 3, 3, 5, 7]。
第二次操作:再次移除前 3 个元素,数组变为 [3, 5, 7],此时数组中的元素互不相同。
因此,答案是 2。

示例 2:
输入: nums = [4,5,6,4,4]
输出: 2
解释:
第一次操作:移除前 3 个元素,数组变为 [4, 4]。
第二次操作:移除所有剩余元素,数组变为空。
因此,答案是 2。

示例 3:
输入: nums = [6,7,8,9]
输出: 0
解释:
数组中的元素已经互不相同,因此不需要进行任何操作,答案是 0。

提示:

1 <= nums.length <= 100
1 <= nums[i] <= 100

二、解题方法

1. 暴力解法

直接双重for循环
!!!需要注意的一点:在每次进行删除操作后,需要将 i 重新赋值为 -1,这是因为删除后,后面的元素会前置,而 i 却是继续往后检索,从而可能导致错过某个元素的检索!!!

代码如下(实例):

/**
 * @param {number[]} nums
 * @return {number}
 */
var minimumOperations = function(nums) {
  // 不知道为什么我总是想到哈希函数
  // 先想想有什么暴力解法,然后再优化

  // 暴力解法:for循环,一旦遇到相等的元素,马上执行移除前三个元素操作(如果少于三个,则移除所有)
  //          每执行一次删除操作,count + 1
  let count = 0
  for(let i = 0; i < nums.length - 1; i++) {
    for(let j = i + 1; j < nums.length; j++) {
      if(nums[i] === nums[j]) {
        if(nums.length < 3) {
          nums.splice(0) // 从索引0开始,删到最后一个
          count++
          i = -1 // 重新开始遍历  !!!!!!
        } else {
          nums.splice(0, 3) // 从索引0开始,移除前三个元素
          count++
          i = -1 // 重新开始遍历  !!!!!!
        }
      }
    }
  }
  return count
}

2. 哈希函数

使用哈希函数来解决,若哈希表中含有该元素,则进行相应的 删除 操作,并且记录count+1
注意:循环结束的 条件

代码如下(示例):

/**
 * @param {number[]} nums
 * @return {number}
 */
var minimumOperations = function (nums) {
  // 不知道为什么我总是想到哈希函数
  // 先想想有什么暴力解法,然后再优化

  // 哈希函数 遍历数组
  // 判断当前元素是否存在于hash表中,如果存在,则进行删除操作,

  // 此处遇到的坑,while循环的语句结束条件的错误!!!
  // 具体表现为:如果当前数组是互不相同的数组了,但是数组的长度又大于0,则while循环不会结束,所以要手动结束
  // 手动结束的条件一直没有想到,不知道怎么写
  // 但是肯定是nums空了或者其中的元素互不相同就结束了
  // 所以干脆在while循环时进行判断,在 nums空了或者其中的元素互不相同 时就不再进行while循环
  let count = 0


  while (nums.length > 0 && nums.length !== new Set(nums).size) {

    const seen = new Set() // 注意,此处集合要在循环体里面定义

    for (let i = 0; i < nums.length; i++) {
      // 如果当前元素存在于哈希表(集合)中,则进行nums的删除操作,并且count的记录 +1,
      if (seen.has(nums[i])) {
        count++
        const num = nums.length >= 3 ? 3 : nums.length
        nums.splice(0, num)
        // nums.splice(0, Math.min(3, nums.length))  二选一
        break
      }
      seen.add(nums[i])
    }
    
    // 此处是结束while循环的关键!!! 不要了,这里有误
    // if (seen.size === nums.length) break

    // 在这行代码中,while 循环的结束条件是通过 if (seen.size === nums.length) break 来判断的,但这可能会导致逻辑不够清晰。可以改进为直接在 while 循环的条件中加入更明确的判断条件。

    // 改进后的 while 循环条件如下:
    // while (nums.length > 0 && new Set(nums).size !== nums.length) {}

    // 这样,循环会在以下两种情况下结束:

    // 数组为空(nums.length === 0)
    // 数组中的元素已经互不相同(new Set(nums).size === nums.length) 因为集合中的元素是互不相同的
    // Set  { 1, 2, 3 }   nums[1, 1, 1, 2, 2, 3]   nums转换成集合就是Set(3) { 1, 2, 3 }
  }

  return count
}

3. 官方题解

3.1 方法一:模拟

思路与算法

题目要求执行操作使得数组中的剩余元素是否互不相同,最直接的方法即每次从数组开头跳过 3 个元素,并检测数组中剩余元素是否存在重复元素,我们可以用一个哈希表来检测数组是否存在重复元素即可。

代码如下(示例):

var minimumOperations = function(nums) {
    let ans = 0;
    for (let i = 0; i < nums.length; i += 3, ans++) {
        if (checkUnique(nums, i)) {
            return ans;
        }
    }
    return ans;
};

const checkUnique = (nums, start) => {
    let seen = new Set();
    for (let i = start; i < nums.length; i++) {
        if (seen.has(nums[i])) {
            return false;
        }
        seen.add(nums[i]);
    }
    return true;
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/minimum-number-of-operations-to-make-elements-in-array-distinct/solutions/3634685/shi-shu-zu-yuan-su-hu-bu-xiang-tong-suo-cay1s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析:
时间复杂度:O(n 2),n 表示给定数组 nums 的长度。每次检测剩余的数组中是否存在重复元素,需要时间最多为 O(n),一共最多需要检测 n 次,因此总的时间为 O(n 2)。
空间复杂度:O(n),n 表示给定数组 nums 的长度。每次检测数组是否含有重复元素时,需要用哈希表记录已经出现的元素,最多存在 n 个元素需要记录,因此需要的空间为 O(n)。

链接:力扣本题官方题解
来源:力扣(LeetCode)

3.2 方法二:倒序遍历

思路与算法

假设重复元素 x 在数组索引 i,j 处出现,若此时满足 i < j,则至少需要移除索引 i 之前所有的元素,则此时问题转换为求数组满足所有元素互不相同的最长后缀。由于每次需要移除 3 个元素,此时移除索引 i 之前的所有元素 nums[0⋯i],至少需要 ⌈(i+1) / 3⌉ = ⌊i / 3⌋ + 1 次移除操作。

假设数组长度为 n,我们尝试倒序遍历数组,同时用 seen 记录已经出现的元素,当遍历到第一个重复元素 nums[i] 时,即该元素已经在当前的后缀中存在,此时返回最少操作次数 ⌊i / 3⌋ + 1 ,如果数组中不存在重复元素,则返回 0。

代码如下(示例):

var minimumOperations = function(nums) {
    const seen = new Array(128).fill(false);
    for (let i = nums.length - 1; i >= 0; i--) {
        if (seen[nums[i]]) {
            return Math.floor(i / 3) + 1;
        }
        seen[nums[i]] = true;
    }
    return 0;
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/minimum-number-of-operations-to-make-elements-in-array-distinct/solutions/3634685/shi-shu-zu-yuan-su-hu-bu-xiang-tong-suo-cay1s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析:
时间复杂度:O(n),n 表示给定数组 nums 的长度。只需遍历一遍数组即可,需要的时间为 O(n)。
空间复杂度:O(n),n 表示给定数组 nums 的长度。需要使用哈希表保存已经遍历过的数据,最多需要保存 n 个元素,需要的空间为 O(n)。

链接:力扣本题官方题解
来源:力扣(LeetCode)

相关文章:

  • 【NLP】 22. NLP 现代教程:Transformer的训练与应用全景解读
  • 高速电路中的电阻、电容的选型及应用
  • SCP-Firmware安全通告:CVE-2024-11863和CVE-2024-11864
  • 数组中的第K个最大元素
  • 运行便携软件提示系统从服务器返回一个参照问题解决
  • CVE重要漏洞复现-Fastjson1.2.24-RCE漏洞
  • 一键部署ai画图环境foooocus colab
  • c++------模板进阶
  • 计算机组成原理 第 1 章 概 论
  • C++基础系列【36】异常处理
  • 系统设计模块之安全架构设计(身份认证与授权(OAuth2.0、JWT、RBAC/ABAC))
  • 使用WindSurf生成贪吃蛇小游戏:从零开始的开发之旅
  • websoket 学习笔记
  • 【LLM】A2A 与 MCP:剖析 AI Agent 互联时代的两种关键协议
  • 路由引入配置
  • JMeter的高并发和高频率和分布式
  • matplotlib练习
  • Spring Boot 使用 SMB 协议
  • Sentinel源码—1.使用演示和简介二
  • 【算法学习笔记】37:扩展中国剩余定理(EXCRT)求解任意线性同余方程组
  • 马上评|遭强奸之后私刑报复,不属正当防卫
  • 林毅夫:中美经济确有脱钩风险,但“完全脱钩”可能性不大
  • A股低开高走,震荡收涨:两市成交10414亿元,4360股收涨
  • 多元布局、抱团取暖……上海这个区和外向型企业坐到一起聊了什么
  • 撤销逾千名留学生签证,特朗普政府面临集体诉讼
  • 特朗普:乌克兰问题谈判短期内若无进展美将不再斡旋