【LeetCode】面试题 03. 数组中重复的数字

【LeetCode】面试题 03. 数组中重复的数字

在这里插入图片描述

一、遍历数组

由于只需要找出数组中任意一个重复的数字,因此遍历数组,遇到重复的数字即返回。为了判断一个数字是否重复遇到,使用集合存储已经遇到的数字,如果遇到的一个数字已经在集合中,则当前的数字是重复数字
在这里插入图片描述

class Solution {
    public int findRepeatNumber(int[] nums) {
        HashSet<Integer> hashSet = new HashSet<>();
        for(int i = 0; i < nums.length; i++){
            if(!hashSet.add(nums[i])){
            return nums[i];
            }   
        }
        return -1;
    }
}
  • 时间复杂度:O(n),遍历数组一遍,使用哈希集合(HashSet),添加元素的时间复杂度为 O(1),故总的时间复杂度是 O(n)
  • 空间复杂度:O(n),不重复的每个元素都可能存入集合,因此占用 O(n) 额外空间

二、原地置换

题干说,在一个长度为 n 的数组 nums 里的所有数字都在 0~n -1 的范围内。此说明含义:数组元素的索引和值是一对多的关系。因此,可以遍历数组并通过交换的操作,使元素的索引与值一一对应。因而,就能通过索引映射对应的值,起到与字典等价的作用。遍历中,第一次遇到数字 x 时,将其交换至索引 x 处,而第二次遇到数字 x 时,一定有 nums[x] = x,此时即可得到一组重复的数字

class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0;
        while(i < nums.length){
            if(nums[i] == i){   //如果当前数和下标对应则 i++ 换一个数
                i++;
                continue;
            }
            //如果当前数对应的下标已经有相同数了,则说明当前数就是一个重复数
            if(nums[nums[i]] == nums[i]) return nums[i];    
            //如果当前数和下标不对应,则可以用它来作为辅助变量,将数置换到对应的下标去
            int t = nums[i];    //保存当前数
            nums[i] = nums[t];  //将对应下标原本的数置换到这里
            nums[t] = t;        //将当前数置换到对应下标
        }
        return -1;
    }
}
  • 时间复杂度 O(N):遍历数组使用 O(N),每轮遍历的判断和交换操作使用 O(1)
  • 空间复杂度 O(1):使用常数复杂度的额外空间

总结

这个题目非常简单,看一眼就知道暴力遍历就能解出来,不过很显然这不是这题考察的重点,面试的时候要是用这种方法就是 0 分。我想了半小时,回头看了一遍四大查找和八大排序,试图找到一些灵感,最终还是没能想出更好的方法。看了题解,第一种是用 HashSet,这是我没想到的,因为我觉得 HashSet 判断元素是否重复,时间复杂度应该是 O(n),再算上遍历一次数组的时间,那么总时间复杂度跟暴力遍历一样都是 O(n^2)。后来百度了一下,得知 HashSet 的 contains() 方法的时间复杂度是 O(1),最坏的情况下是 O(n),但平均情况更接近 O(1)。第二种方法就比较巧妙了,原地置换,充分利用了题干的条件,一开始我是对题干那句话有想法的,但是想不出该怎么用,不得不佩服想出这种算法的人!在复写这个算法的时候我一开始在纠结为什么这里一定要用 while 而不用 for,后来我才明白,这个循环不是每次都需要 i++ 的,它的目的是把每个数和与之对应的数组下标联系起来,那么只有当 i 和 nums[i] 对应的时候才需要改变 i 的值,这也是为什么这个算法叫原地置换,下标本身不需要变,只要把 nums[i] 换出去就好了,换进来的又是一个新的数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值