剑指offer-数组中重复的数字

题目描述

  • 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
  • 地址:牛客地址

问题分析

  • 使用额外空间:
    • HashSet,遍历数组,看set中是否存在当前元素,若已经存在,那么该元素便是重复元素,直接返回。若不存在,降之存入Set
    • 数组,count[i] 表示 值为 i 的元素出现了几次。遍历到 i元素时,看count[i]是否为0,若不为0,说明以前出现过。若为0,次数加1。
      时间复杂度:O(N) 空间复杂度:O(N)
  • 不用额外空间:
    • 注意题干,所有数字都是处于 0~n-1的范围内,所以可以在不使用额外空间的情况下,将 值为 i 的元素存到 数组的 i 位置处,使得 num[i] = i, 这便是一种 hash 的思想,如果数组总出现了重复元素,这两个元素都对应同一个 hash 地址,那么势必会引起冲突,发生冲突时便返回冲突元素即可,这便是数组中重复的数字。
    • 那么如何调整数组,使 0~ n-1 装入对应位置中,使得 num[i] = i 呢?
      从前到后遍历数组,看 num[i] 是否等于 i,若等于,则检测下一位置,若不等于,那么按照 hash规则, num[i] 应该放在 num[i] 处,即使得num[num[i]] = num[i],但对于该题,必须先检验 num[i] 位置处是否已经放置好了正确的元素,即 检测 num[num[i]] = num[i] 。
      • 若等于,那么当前元素按规则也应该放在那位置,说明发生了冲突,出现了重复元素。直接返回该元素
      • 若不等于,说明尚无冲突,那么 将 num[i] 放入 num[i] 位置,num[i] 位置上的原元素放在 i 位置,即交换 i 位置与 num[i] 位置上的元素。然后继续检验 num[i] 是否等于 i。直至等于,然后检查下一位置。
    • 该方法直接改变原数组,并且对于每一个元素而讲,最多经历两次交换,便可处于正确位置,所以 时间复杂度:O(N) 空间复杂度:O(1)

经验教训

  • 对于固定范围的数据,在固定空间下如何用 hash思想 来检重
  • 如何调整数组,使 0~ n-1 装入对应位置中,使得 num[i] = i 呢?并且时间复杂度:O(N) 空间复杂度:O(1) 。有种连环怼的洗牌思想。
  • 交换时出现的愚蠢的错误

代码实现

  • HashSet
    public boolean duplicate1(int numbers[],int length,int [] duplication) {
        if(numbers == null || length == 0 || length == 1) {
            return false;
        }
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < length; i++) {
            if (set.contains(numbers[i])) {
                duplication[0] = numbers[i];
                return true;
            }
            set.add(numbers[i]);
        }
        return false;
    }
  • hash
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers == null || length <= 1) {
            return false;
        }
        for (int i = 0; i < length; i++) {
            while (numbers[i] != i) {

                if (numbers[numbers[i]] == numbers[i]) {
                    duplication[0] = numbers[i];
                    return true;
                }
                // swap(numbers[0] , numbers[numbers[0]])
                int temp = numbers[i];
                //注意,是temp!!!
                numbers[i] = numbers[temp];
                numbers[temp] = temp;
            }
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值