|
| 1 | +# 3289. The Two Sneaky Numbers of Digitville |
| 2 | + |
| 3 | +In the town of Digitville, there was a list of numbers called `nums` containing integers from `0` to `n - 1`. |
| 4 | +Each number was supposed to appear exactly once in the list, however, two mischievous numbers sneaked in an additional time, making the list longer than usual. |
| 5 | + |
| 6 | +As the town detective, your task is to find these two sneaky numbers. |
| 7 | +Return an array of size two containing the two numbers (in any order), so peace can return to Digitville. |
| 8 | + |
| 9 | +**Constraints:** |
| 10 | + |
| 11 | +- `2 <= n <= 100` |
| 12 | +- `nums.length == n + 2` |
| 13 | +- `0 <= nums[i] < n` |
| 14 | +- The input is generated such that `nums` contains exactly two repeated elements. |
| 15 | + |
| 16 | +## 基礎思路 |
| 17 | + |
| 18 | +本題要求在一個應該包含 `0` 到 `n - 1` 各一次的整數列表中,找出那兩個偷偷重複出現的數字。 |
| 19 | +題目保證: |
| 20 | + |
| 21 | +* 整體長度為 `n + 2`(比預期多出 2 個元素); |
| 22 | +* 共有且僅有兩個數字出現兩次。 |
| 23 | + |
| 24 | +在思考解法時,我們需要掌握幾個重點: |
| 25 | + |
| 26 | +* 每個數字介於 `0` 到 `n - 1`,範圍固定; |
| 27 | +* 恰有兩個數字重複出現兩次; |
| 28 | +* 其餘數字皆出現一次,因此我們可透過「出現次數」辨識重複者。 |
| 29 | + |
| 30 | +為了解決這個問題,我們可以採取以下策略: |
| 31 | + |
| 32 | +* **建立頻率表**:使用雜湊結構(如 `Map`)來記錄每個數字出現次數; |
| 33 | +* **偵測重複出現**:在每次更新頻率時檢查是否等於 2,若是則紀錄該數; |
| 34 | +* **輸出結果**:題目保證正好兩個重複數,返回長度為 2 的陣列即可。 |
| 35 | + |
| 36 | +此法邏輯直觀、實作簡潔,且在題目限制下能以線性時間完成。 |
| 37 | + |
| 38 | +## 解題步驟 |
| 39 | + |
| 40 | +### Step 1:建立頻率表與結果陣列 |
| 41 | + |
| 42 | +宣告一個 `Map` 來記錄每個數字出現的次數,並建立空陣列用於儲存找到的重複數字。 |
| 43 | + |
| 44 | +```typescript |
| 45 | +// 建立頻率映射表與儲存重複數的陣列 |
| 46 | +const frequencyMap = new Map<number, number>(); |
| 47 | +const duplicates: number[] = []; |
| 48 | +``` |
| 49 | + |
| 50 | +### Step 2:遍歷整個陣列並統計出現次數 |
| 51 | + |
| 52 | +逐一讀取每個數字,若該數尚未出現則設為 1,否則累加次數。 |
| 53 | +若某數字次數達到 2,代表該數為重複數,立即加入結果陣列。 |
| 54 | + |
| 55 | +```typescript |
| 56 | +// 逐一檢查 nums 中的每個數字 |
| 57 | +for (let i = 0; i < nums.length; i++) { |
| 58 | + // 更新該數字的出現次數 |
| 59 | + frequencyMap.set(nums[i], (frequencyMap.get(nums[i]) || 0) + 1); |
| 60 | + |
| 61 | + // 若該數字出現第二次,加入結果陣列 |
| 62 | + if (frequencyMap.get(nums[i]) === 2) { |
| 63 | + duplicates.push(nums[i]); |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +### Step 3:返回結果陣列 |
| 69 | + |
| 70 | +當整個陣列處理完畢後,`duplicates` 陣列即包含兩個重複數字,直接回傳即可。 |
| 71 | + |
| 72 | +```typescript |
| 73 | +// 返回兩個找到的重複數字 |
| 74 | +return duplicates; |
| 75 | +``` |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +## 輔助函數完整實作 |
| 80 | + |
| 81 | +```typescript |
| 82 | +function getSneakyNumbers(nums: number[]): number[] { |
| 83 | + // 建立頻率映射表與儲存重複數的陣列 |
| 84 | + const frequencyMap = new Map<number, number>(); |
| 85 | + const duplicates: number[] = []; |
| 86 | + |
| 87 | + // 逐一檢查 nums 中的每個數字 |
| 88 | + for (let i = 0; i < nums.length; i++) { |
| 89 | + // 更新該數字的出現次數 |
| 90 | + frequencyMap.set(nums[i], (frequencyMap.get(nums[i]) || 0) + 1); |
| 91 | + |
| 92 | + // 若該數字出現第二次,加入結果陣列 |
| 93 | + if (frequencyMap.get(nums[i]) === 2) { |
| 94 | + duplicates.push(nums[i]); |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + // 返回兩個找到的重複數字 |
| 99 | + return duplicates; |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +## 時間複雜度 |
| 104 | + |
| 105 | +- 需遍歷整個陣列一次以建立頻率表; |
| 106 | +- `Map` 的查詢與更新操作平均為常數時間。 |
| 107 | +- 總時間複雜度為 $O(n)$。 |
| 108 | + |
| 109 | +> $O(n)$ |
| 110 | +
|
| 111 | +## 空間複雜度 |
| 112 | + |
| 113 | +- 額外使用一個 `Map` 來記錄出現次數; |
| 114 | +- `duplicates` 陣列只儲存兩個元素,為常數級別。 |
| 115 | +- 總空間複雜度為 $O(n)$。 |
| 116 | + |
| 117 | +> $O(n)$ |
0 commit comments