[LeetCode] 287. Find the Duplicate Number — Linked List — Medium

LuLu
4 min readAug 24, 2023

題目:

Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.

There is only one repeated number in nums, return this repeated number.

You must solve the problem without modifying the array nums and uses only constant extra space.

JavaScript

var findDuplicate = function(nums) {

};

Example 1:

Input: nums = [1,3,4,2,2]
Output: 2

Example 2:

Input: nums = [3,1,3,4,2]
Output: 3

觀念:

  • 因為要維持 space = BIgO(1) 所以不能用 hashmap
  • 因為不能修改 原本的陣列,所以不能用 sort (也不能建立一個新的因為 space BigO(1) )
  • 因為重複的數字可能不只一個,所以不能把總數加起來在來比對差,例如 [1,1,1,1,1,1]
  • 我們可以利用的是:數字一定是在 n (陣列長度) 裡面,代表不會超過 n — 1
  • 我們還可以利用:只有一個數字是重複的
  • 可以用 Linked List 的概念來想,然後每一個數字代表的是 index pointer,例如 [1,3,4,2,2] 代表的是 1 → 3 → 2 → 4 → loop to 2 again。當一個數字有兩個指標指向它,它就是一個循環的起點。
  • 需要使用 Floyd判圈算法,也就是龜兔賽跑算法

Floyd 判圈算法:

要找到循環的起點有兩個步驟:

  1. 找到slow 跟 fast 相遇的點 (meeting point: m)
  2. 在開頭建立一個新的 slow2,slow 從 m 繼續每次走一步,slow2 從開頭走,找到兩者相遇的點,這就是循環的開頭 (beginning point : b),這也就是我們要找的重複的數字。

(詳細解釋可以看最下方參考連結的影片)

Javascript 解題:

var findDuplicate = function (nums) {
// 1. find the meeting point of slow and fast
let slow = 0
let fast = 0
while (true) {
slow = nums[slow]
fast = nums[nums[fast]] // move twice
if (slow === fast) {
break // currently slow is at the meeting point
}
}
// 2. find the point where the second slow meet with the slow
let slow2 = 0 // start a new slow a index 0
while (true) {
slow = nums[slow]
slow2 = nums[slow2]
if (slow === slow2) {
return slow // that is the beginning of the cycle.
}
}
}

解題步驟:

  • 第一步:找到 meeting point
  • 建立兩個指標,fast 跟 slow,fast 一次移動一格,slow 兩格
  • 使用 while loop,兩個指標開始跑,直到跑到一個相遇的點上,結束 loop
  • 第二部:找到循環起始點(重複數字)
  • 建立一個新指標,slow2,起始點在開頭
  • 使用 while loop,slow 跟 slow2 開始跑,直到跑到一個相遇的點上,結束 loop
  • 回傳 slow (重複的數字)

參考:

https://www.youtube.com/watch?v=wjYnzkAhcNk

--

--