剑指offer-面试题3:数组中重复的数字

这篇博客介绍了四种解决寻找数组中重复数字的方法,包括排序、哈希表、数组模拟哈希以及原地置换。每种方法都详细分析了其时间复杂度和空间复杂度,适用于不同的场景。排序法利用了异或运算,哈希表法通过存储元素出现情况直接找出重复项,数组模拟哈希法则是在有限范围内利用辅助数组,原地置换法通过改变数组结构找到重复元素。这些方法都是在数组性质基础上进行的高效解题策略。
摘要由CSDN通过智能技术生成

题目描述

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入: [2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3

限制: 2 <= n <= 100000

方法一(排序)

1.解题思路

直接对原数组进行排序,然后重复的数字一定和它的下一位相同,通过异或运算进行判断,如果结果为0,则相同,直接返回

2.代码实现
class Solution {
    public int findRepeatNumber(int[] nums) {
        Arrays.sort(nums);
        int n=nums.length;
        for(int i=0;i<n;i++){           
            if((nums[i]^nums[i+1])==0){
                return nums[i];
            }
        }
        return -1;
    }
}        
3.复杂度分析
  • 时间复杂度:由于用到了排序接口,时间复杂度为O(nlogn)
  • 空间复杂度:O(1)

方法二(哈希表)

1.解题思路

遍历的过程中,用一个哈希表来存储元素,如果这个过程中,发现当前元素已经在哈希表里面,则可以直接返回

2.代码实现
class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set=new HashSet<>();
        int res=-1;
        for(int num:nums){
            if(set.contains(num)){
                res=num;
                break;
            }
            set.add(num);
        }
        return res;
    }
} 
3.复杂度分析
  • 时间复杂度:需要遍历整个数组,所以复杂度为O(n)
  • 空间复杂度:需要额外哈希表的内存空间,复杂度为O(n)

方法三(组数模拟哈希)

1.解题思路

由于数组长度和数组中元素大小有范围限制,所以我们可以考虑用一个boolean型数组来模拟哈希表,如果数组中某下标对应值为true,则表示已经存储过,是重复元素,可直接返回

2.代码实现
class Solution {
    public int findRepeatNumber(int[] nums) {
        int n=nums.length;
        boolean[] f=new boolean[n];
        for(int i=0;i<n;i++){           
            if(f[nums[i]]){
                return nums[i];
            }
            f[nums[i]]=true;
        }
        return -1;
    }
}
3.复杂度分析
  • 时间复杂度:需要遍历整个数组,所以复杂度为O(n)
  • 空间复杂度:需要额外数组的内存,复杂度为O(n)

方法四(原地置换)

1.解题思路

由于数组中元素个数为n个,范围是0到n-1,所以我们可以考虑把数组中的元素放在下标等于它自身数值的位置,即做一个等值映射(比如0放在下标为0的位置,1放在下标为1的位置),那么在映射的过程中,由于存在重复的元素,所以重复的元素一定会被再次映射,如果发现需要再次映射,则直接返回,就是重复的那个元素

步骤元素变化
第1步2 3 1 0 2 5 3
第2步1 3 2 0 2 5 3
第3步3 1 2 0 2 5 3
第4步0 1 2 3 2 5 3
第5步返回 2
2.代码实现
class Solution {
    public int findRepeatNumber(int[] nums) {
        int n=nums.length;
        for(int i=0;i<n;i++){
            while(nums[i]!=i){
                if(nums[i]==nums[nums[i]]){
                    return nums[i];
                }
                int temp=nums[i];
                nums[i]=nums[temp];
                nums[temp]=temp;
            }
        }
        return -1;
    }
}
3.复杂度分析
  • 时间复杂度:需要遍历整个数组,所以复杂度为O(n)
  • 空间复杂度:由于是原地置换,不需要额外的空间,所以复杂度为O(n)

剑指offer全集入口: 请戳这里

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值