剑指 Offer 03:数组中重复的数字

该篇博客探讨了一道编程题,即如何在给定范围内查找数组中的重复数字。博主首先介绍了使用HashSet的常规解法,然后通过利用数组特性,将空间复杂度降低到O(1)。最后,提出一种利用数组自身下标的优化解法,通过不断交换元素,找到重复数字。博客强调了仔细阅读题目条件的重要性,并提供了LeetCode上的题目链接以供实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:找出数组中重复的数字。

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

示例 1:

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

输出:2 或 3

题意很容易理解,就是在数组里面找到重复的数字,而且是任意一个,随着正常思路,就是遍历数组,然后用一个 set 来保存遍历过的元素,如果遍历元素的时候,发现 set 中已经存在的此元素,说明重复了,直接返回即可。

随着这个思路,很容易就写下以下的代码:

class Solution {
    public int findRepeatNumber(int[] nums) {
        int len = nums.length;
        Set<Integer> numsSet = new HashSet();
        for (int i = 0; i < len; i++) {
          if (numsSet.contains(nums[i])) {
            return nums[i];
          }
          numsSet.put(nums[i]);
        }
        return -1;
    }
}

以上解法没啥毛病,时间复杂度 O(n),空间复杂度O(n)。

细心的同学肯定还注意到题干的一句话:数组 nums 里的所有数字都在 0~n-1 的范围内。

所以可以利用数组来替代 set 的操作:


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

以上解法,稍微思考一下应该不难理解。

时间复杂度 O(n),空间复杂度O(n)。

此时再来看看时间复杂度能否优化,发现好像并不行,只能遍历一遍才能得知重复,那空间复杂度呢?能否原地处理?

可以的!

根据数组 nums 里的所有数字都在 0~n-1 的范围内这句话的含义,我们可以得知数组内部的值不会大于数组长度,所以每个值都能找到对应的下标位置

举个例子: 如果数组里面有 5 ,那么数组长度必定大于等于 6 ,所以一定存在 num[5] 。

如果我们把数组的所有元素搬迁到对应下标的位置,那么重复的数组必定会争抢相同下标的位置,根据这个条件就可以得知重复。

所以看下以下代码:

class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0, len = nums.length;
        while(i < len) {
          //如果当前位置的值等于当前下标,那说明不用移动。
          if(nums[i] == i) { 
            i++;
            continue;
          }
          //如果当前位置的值,已经在对应下标的位置,存在,说明重复了,直接返回
          if(nums[i] == nums[nums[i]]) { 
            return nums[i];
          } 
          // 交换值,使得数组对应下标存储下标的值。
          int temp = nums[i];
          nums[i] = nums[temp];
          nums[temp] = temp;
        }
        return -1;
    }
}

时间复杂度 O(n),空间复杂度O(1)。

所以要好好看题目,题目有些条件其实就是给予我们启发的


一道简单题
链接如下:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值