哈希表题目:在长度 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;
    }
}

复杂度分析

  • 时间复杂度: 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;
    }
}

复杂度分析

  • 时间复杂度: 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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值