• 哈希表题目:在长度 2N 的数组中找出重复 N 次的元素


    题目

    标题和出处

    标题:在长度 2N 的数组中找出重复 N 次的元素

    出处:961. 在长度 2N 的数组中找出重复 N 次的元素

    难度

    2 级

    题目描述

    要求

    给你一个具有以下性质的整数数组 nums \texttt{nums} nums

    • nums.length = 2 × n \texttt{nums.length} = \texttt{2} \times \texttt{n} nums.length=2×n
    • nums \texttt{nums} nums 包含 n + 1 \texttt{n} + \texttt{1} n+1不同的元素。
    • nums \texttt{nums} nums 中恰好有一个元素重复了 n \texttt{n} n 次。

    返回重复了 n \texttt{n} n 次的元素。

    示例

    示例 1:

    输入: nums   =   [1,2,3,3] \texttt{nums = [1,2,3,3]} nums = [1,2,3,3]
    输出: 3 \texttt{3} 3

    示例 2:

    输入: nums   =   [2,1,2,5,3,2] \texttt{nums = [2,1,2,5,3,2]} nums = [2,1,2,5,3,2]
    输出: 2 \texttt{2} 2

    示例 3:

    输入: nums   =   [5,1,5,2,5,3,5,4] \texttt{nums = [5,1,5,2,5,3,5,4]} nums = [5,1,5,2,5,3,5,4]
    输出: 5 \texttt{5} 5

    数据范围

    • 2 ≤ n ≤ 5000 \texttt{2} \le \texttt{n} \le \texttt{5000} 2n5000
    • nums.length = 2 × n \texttt{nums.length} = \texttt{2} \times \texttt{n} nums.length=2×n
    • 0 ≤ nums[i] ≤ 10 4 \texttt{0} \le \texttt{nums[i]} \le \texttt{10}^\texttt{4} 0nums[i]104
    • nums \texttt{nums} nums 包含 n + 1 \texttt{n} + \texttt{1} n+1不同的元素,其中有一个元素重复了 n \texttt{n} n

    解法一

    思路和算法

    这道题的求解关键在于数组 nums \textit{nums} nums 的性质。

    数组 nums \textit{nums} nums 的长度是 2 n 2n 2n,即有 2 n 2n 2n 个元素,其中有 n + 1 n + 1 n+1不同的元素且恰好有一个元素重复了 n n n 次,说明除了这个重复 n n n 次的元素以外,还有其余的 n n n 个元素,其余的 n n n 个元素都不等于重复 n n n 次的元素且各不相同,因此其余的 n n n 个元素各出现一次。

    由于数组 nums \textit{nums} nums 的其余的 n n n 个元素各出现一次,因此重复了 n n n 次的元素是唯一在数组 nums \textit{nums} nums 中出现超过一次的元素,只要在数组中寻找出现超过一次的元素,即为重复 n n n 次的元素。

    判断一个元素是否重复可以使用哈希集合。遍历数组 nums \textit{nums} nums,对于每个元素,如果该元素不在哈希集合中则将其加入哈希集合,如果该元素已经在哈希集合中则为重复元素,将其返回即可。

    class Solution {
        public int repeatedNTimes(int[] nums) {
            int repeat = -1;
            Set<Integer> set = new HashSet<Integer>();
            for (int num : nums) {
                if (!set.add(num)) {
                    repeat = num;
                    break;
                }
            }
            return repeat;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    复杂度分析

    • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度的一半。需要遍历数组 nums \textit{nums} nums 寻找重复元素,最多需要遍历 n + 1 n + 1 n+1 个不同元素。

    • 空间复杂度 O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度的一半。需要使用哈希表存储数组 nums \textit{nums} nums 中的元素,最多需要存储 n + 1 n + 1 n+1 个元素。

    解法二

    思路和算法

    考虑重复 n n n 次的元素在数组 nums \textit{nums} nums 中所在下标的距离,则一定存在两个相等的元素的下标距离不超过 3 3 3,因此对于任意 1 ≤ i < 2 n 1 \le i < 2n 1i<2n,遍历所有满足 max ⁡ ( 0 , i − 3 ) ≤ j < i \max(0, i - 3) \le j < i max(0,i3)j<i j j j,如果找到 nums [ i ] = nums [ j ] \textit{nums}[i] = \textit{nums}[j] nums[i]=nums[j],则 nums [ i ] \textit{nums}[i] nums[i] 即为重复 n n n 次的元素。

    为了寻找重复 n n n 次的元素,必须遍历下标距离为 1 1 1 3 3 3 的每一对元素寻找相等元素,而不能只遍历下标距离为 1 1 1 2 2 2 的每一对元素寻找相等元素。当 n = 2 n = 2 n=2 时,如果 nums = [ 1 , 2 , 3 , 1 ] \textit{nums} = [1, 2, 3, 1] nums=[1,2,3,1],则重复元素出现了 2 2 2 次且下标距离为 3 3 3,如果只考虑下标距离为 1 1 1 2 2 2 的每一对元素则无法找到重复元素。

    证明

    数组 nums \textit{nums} nums 一定存在两个相等的元素的下标距离不超过 3 3 3。该结论证明如下。

    使用反证法。假设数组 nums \textit{nums} nums 的任意两个相等的元素的下标距离都超过 3 3 3,则下标距离至少为 4 4 4。用 start \textit{start} start end \textit{end} end 分别表示重复元素所在的最小下标和最大下标,则有 end − start ≥ 4 ( n − 1 ) \textit{end} - \textit{start} \ge 4(n - 1) endstart4(n1)

    由于数组 nums \textit{nums} nums 的长度是 2 n 2n 2n,下标范围是 [ 0 , 2 n − 1 ] [0, 2n - 1] [0,2n1],因此有 end − start ≤ 2 n − 1 \textit{end} - \textit{start} \le 2n - 1 endstart2n1

    为了同时满足 end − start ≥ 4 ( n − 1 ) \textit{end} - \textit{start} \ge 4(n - 1) endstart4(n1) end − start ≤ 2 n − 1 \textit{end} - \textit{start} \le 2n - 1 endstart2n1,必须有 4 ( n − 1 ) ≤ 2 n − 1 4(n - 1) \le 2n - 1 4(n1)2n1,整理得 n ≤ 3 2 n \le \dfrac{3}{2} n23

    由于题目要求 n ≥ 2 n \ge 2 n2,因此 n ≤ 3 2 n \le \dfrac{3}{2} n23 不符合题目要求,数组 nums \textit{nums} nums 的任意两个相等的元素的下标距离都超过 3 3 3 的假设不成立。

    因此数组 nums \textit{nums} nums 一定存在两个相等的元素的下标距离不超过 3 3 3

    代码

    class Solution {
        public int repeatedNTimes(int[] nums) {
            int repeat = -1;
            boolean flag = false;
            int length = nums.length;
            for (int i = 1; i < length && !flag; i++) {
                for (int j = Math.max(0, i - 3); j < i; j++) {
                    if (nums[i] == nums[j]) {
                        repeat = nums[i];
                        flag = true;
                        break;
                    }
                }
            }
            return repeat;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    复杂度分析

    • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度的一半。需要遍历数组 nums \textit{nums} nums 一次,对于每个元素,最多需要判断该元素的前面 3 3 3 个元素是否与该元素相等,因此总时间复杂度是 O ( 3 × 2 n ) = O ( 6 n ) = O ( n ) O(3 \times 2n) = O(6n) = O(n) O(3×2n)=O(6n)=O(n)

    • 空间复杂度: O ( 1 ) O(1) O(1)

  • 相关阅读:
    从3D ToF到智能座舱系统方案,英飞凌如何赋能未来出行?
    黄金投资面对K线图有哪些好用的交易策略?
    ROC曲线
    MyBatis 与 MyBatis-Plus 的区别
    逍遥自在学C语言 | 条件控制的正确使用姿势
    Java设计模式之创建型模式
    Qt http
    WorkPlus AI助理知识问答机器人,助力企业级私有化AI构建
    main函数执行前执行和执行后执行
    C语言--给定一行字符串,获取其中最长单词【图文详解】
  • 原文地址:https://blog.csdn.net/stormsunshine/article/details/121452329