天天看點

劍指offer - 數組中重複的數字 - JavaScript

題目描述:找出數組中重複的數字。在一個長度為 n 的數組 nums 裡的所有數字都在 0 ~ n-1 的範圍内。數組中某些數字是重複的,但不知道有幾個數字重複了,也不知道每個數字重複了幾次。請找出數組中任意一個重複的數字。

題目描述

找出數組中重複的數字。

在一個長度為 n 的數組 nums 裡的所有數字都在 0 ~ n-1 的範圍内。數組中某些數字是重複的,但不知道有幾個數字重複了,也不知道每個數字重複了幾次。請找出數組中任意一個重複的數字。

解法 1: 使用哈希表

哈希表的結構是:number-boolean,number 就是數組中的數字,boolean 代表數字是否出現過。

整體的流程是:周遊數組中的數字,檢查是否出現過,如果出現過,那麼傳回此數字。代碼實作如下:

// ac位址:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
// 原文位址:https://xxoo521.com/2020-02-14-repeat-number/

/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function(nums) {
    const map = {};
    for (const num of nums) {
        if (!map[num]) {
            map[num] = true;
        } else {
            return num;
        }
    }
};           

複制

由于使用了哈希表,是以空間複雜度是 O(N)。需要周遊一次,時間複雜度是 O(1)。

解法 2: 原地哈希(推薦)

從題目描述可以知道,所有數字都在 0 ~ n-1 的範圍内。是以不需要額外開辟空間,每次周遊時,檢查目前元素是否放在了正确位置上(例如元素 i 應該放在下标為 i 的位置上)。如果放在了正确位置上,那麼繼續循環。否則:

  • 下标為 num 的元素 === num,說明目前元素 num 是重複的,直接傳回
  • 下标為 num 的元素 !== num,交換目前元素和下标為 num 的元素,将目前元素放入到正确位置上

代碼實作如下:

// ac位址:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
// 原文位址:https://xxoo521.com/2020-02-07-half-number/

/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function(nums) {
    const length = nums.length;
    for (let i = 0; i < length; ++i) {
        //檢測下标為i的元素是否放在了位置i上
        while ((num = nums[i]) !== i) {
            if (num === nums[num]) {
                return num;
            }
            [nums[i], nums[num]] = [nums[num], nums[i]];
        }
    }
};           

複制

這裡要注意的是,第二種情況交換完元素後,應該繼續檢測下标為 i 的元素是否放在了位置 i 上,實作上使用

while

内循環即可。以

[1, 3, 2, 3]

為例,第一次交換後,變為

[3, 1, 2, 3]

,如果沒有内循環,那麼就會跳過第一個 3,繼續周遊,而後面的元素又恰巧都在正确位置上,最終沒有檢查出重複元素。特别感謝@徹的提示。

錯誤代碼

這段代碼在 leetcode 上可以 ac,建議官方添加測試用例:

[1, 3, 2, 3]

// ac位址:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
// 原文位址:https://xxoo521.com/2020-02-14-repeat-number/

/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function(nums) {
    const length = nums.length;
    for (let i = 0; i < length; ++i) {
        const num = nums[i];
        if (num === i) {
            continue;
        }

        if (num === nums[num]) {
            return num;
        } else {
            [nums[i], nums[num]] = [nums[num], nums[i]];
        }
    }
};           

複制