数组中重复的数字

一、需求

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

二、暴力法

2.1  思路分析

  1. 利用双重for循环,两两比较,比如第1个数和第2,3,4,...,n个数比较,然后第2个数和第3,4,5,...,n个数比较,第 i 个数和第 i + 1~n个数比较,直到出现重复元素,就返回;
  2. 本题数组的最大长度为10^5,因此当时间复杂度为O(n^2)时,存在超时问题;

2.2  代码实现

class Solution {
    public int findRepeatNumber(int[] nums) {
        for(int i = 0; i < nums.length; i++) {
            for(int j = i + 1; j < nums.length; j++) {
                if(nums[i] == nums[j]) return nums[i];
            }
        }
        return 0;
    }
}

 2.3  复杂度分析

  • 时间复杂度为O(n^2);
  • 空间复杂度为O(1);

三、哈希表法

3.1  思路分析

  1. 哈希表也有很多种,这里用HashSet比较合适,HashMap也能做,但它涉及到了键值对,在这里只需用用Set判断是否包含重复元素就好;
  2. 遍历数组,若Set中已经包含了某元素,那么直接返回;

3.2  代码实现

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int num : nums) {
            if(!set.add(num)) {
                return num;
            }
        }
        return 0;
    }
}

3.3  复杂度分析

  • 时间复杂度为O(n);
  • 空间复杂度为O(n);

四、排序法

4.1  思路分析

  1. 首先将数组进行排序,然后就遍历数组,看看相邻元素是否有重复的,如果有重复的,就返回这个元素;

4.2  代码实现

class Solution {
    public int findRepeatNumber(int[] nums) {
        Arrays.sort(nums);
        for(int i = 1; i < nums.length; i++) {
            if(nums[i] == nums[i - 1]) return nums[i];
        }
        return 0;
    }
}

4.3  复杂度分析

  • 时间复杂度为O(n);
  • 空间复杂度为O(1);

五、原地置换法

5.1  思路分析

  1. 题目要求数组中的元素的取值范围是:0~n-1,比如数组[2,3,1,0,2,5,3],我们要将数组各元素值,安排到对应的索引上,比如数组首元素2对应的索引是0,应该把它安排到索引2上;
  2. 这就有了一个问题,什么时候需要安排索引呢?我们定义变量 i 来遍历数组,当 nums[i] == i时就不需要安排,当nums[i] != i 时需要安排;
  3. 那么另外一个问题,如何安排索引?比如现在 i = 0,此时 i != nums[i],即0 != 2,需要把 2 放到索引 2 处,故交换的是 2 和 1,2本身就是nums[i],那么1用什么表示呢,1 = nums[2] = nums[nums[i]],对,就这样,交换它们的位置;
  4. 遇到重复元素怎么处理?假设第一个 2 已结在索引 2 处,现在 i 已经到了第二个 2 的位置,即 i = 4,现在要判断是不是有两个 2,首先nums[i] == 2,然后另一个2 == nums[nums[i]],也就是说当nums[ i] == nums[nums[i]]时,就出现了重复元素,此时,我们返回该元素。

5.2  代码实现

class Solution {
    // 原地置换法
    public int findDuplicate(int[] nums) {
        for (int i = 0; i < nums.length;) {
            // nums[i]已在索引i处
            if (nums[i] == i) {
                i++;
                continue;
            }
            // 这个判断要在前面
            if (nums[i] == nums[nums[i]]) {
                return nums[i];
            }
            // 将nums[i]置于指定索引处
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return 0;
    }
}

5.3  复杂度分析

  • 时间复杂度为O(n);
  • 空间复杂度为O(1);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值