《剑指offer》面试题3:数组中重复的数字(JavaScript)


欢迎并且感谢交流区探讨和指正

题目

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

方法一:遍历交换法(最优解)

时间复杂度:O(n)
空间复杂度:O(1)

分析

首先要明确一个事,输入数组 nums 的长度为 n,数组下标为 0 ~ n-1,且数组中的数的范围是 0 ~ n-1

  1. 若数组中没有重复数字,将数组排序后,数组中存储的值将与其下标值一一对应相等
  2. 当数组中有重复数字时,此时将数组排序,必有一个现象:最少存在一个重复的值不仅存在于其对应的下标处,还存在于别处

该方法正是利用了这个规律,解题思路如下

从头开始扫描数组,先判断该位置的数是否与下标相等,即该数是否在排序后它应该在的位置

  1. 若相等,i++ 继续判断下一个
  2. 若不相等,即 nums[i] != i,此时应该让它去它该去的地方,但是那个位置上是否已经存在重复值了呢?判断 nums[nums[i]] 与 nums[i] 是否相等
    1. 若相等,存在重复值,结束
    2. 若不相等,将二者交换,并对交换回来的数再次从头进行判断

只需要一次遍历,所以时间复杂度为 O(n)
需要有限个临时变量,所以空间复杂度为 O(1)

代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function (nums) {
    var i = 0;
    while (i < nums.length) {
        if (nums[i] === i) i++
        else if (nums[nums[i]] != nums[i]) {
            var temp = nums[nums[i]]
            nums[nums[i]] = nums[i]
            nums[i] = temp
        } else {
            return nums[i]
        }
    }
    return -1
};

方法二:哈希表法

时间复杂度:O(n)
空间复杂度:O(n)

分析

只需要一次遍历,所以时间复杂度为 O(n)
需要一个长度为 n 的哈希表存储数据,所以空间复杂度为 O(n)

代码

var findRepeatNumber = function (nums) {
    var arr = new Array(nums.length)
    for (var i = 0; i < nums.length; i++) {
        if (arr[nums[i]] === 1) {
            return nums[i]
        } else {
            arr[nums[i]] = 1
        }
    }
};

方法三:先排序后遍历

时间复杂度:O(nlgn)
空间复杂度:O(1)

分析

先将数组排序,时间复杂度为 O(nlgn)
然后从头遍历找到重复数字,时间复杂度为 O(n)

代码

var findRepeatNumber = function (nums) {
    nums.sort()
    for (var i = 1; i < nums.length; i++) {
        if (nums[i] === nums[i - 1]) {
            return nums[i]
        }
    }
    return -1
};

拓展

在一个长度为 n+1 的数组 nums 里的所有数字都在 0~n 的范围内。
所以数组中至少有一个数字是重复的。(抽屉原理)
请找出数组中任意一个重复的数字,但不能修改原数组。
输入:[2, 3, 5, 4, 3, 2, 6, 7]
输出:2 或 3

分析

复习一下二分查找

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值