↓快轉到主要內容
  1. LeetCode/

LeetCode 2709: Greatest Common Divisor Traversal

·2 分鐘· ·
LeetCode Hard Math Number-Theory Union-Find Sieve Gcd Array
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2025-08-07

  • 提交紀錄:TLE → RE → WA ×2 → TLE ×2(2025-08-07)→ AC → WA → RE → AC(2026-10-12)

解題思路
#

「任兩個 index 都能互通」⇔ 所有 index 在同一個連通塊。跟 LeetCode 952 一樣,用質因數代替兩兩 GCD。

這裡讓 Union-Find 的節點是值:先用 SPF 篩到 max(nums),每個數字跟它的每個質因數合併。最後檢查所有數字是不是同一個根。

1 的特殊情況:1 沒有質因數,跟誰都連不到。

  • 只有一個元素時,沒有「兩個 index」要檢查,答案是 True(就算是 [1])。
  • 超過一個元素而且有 1:一定是 False。

我的嘗試
#

版本問題
第一版 TLE兩兩算 GCD,O(n^2)
RE想先去重,寫成 nums = set(nums),set 不能用 index 存取
WA改成 list(set(nums)) 去重,但兩個 1 被去重成一個。例如 [1, 1]:兩個 1 互相連不到,答案是 False,回傳 True
WA加上「有 1 就回傳 False」,但 [1] 只有一個元素時答案是 True
兩次 TLE還是兩兩算 GCD
AC(隔年)改成依質因數合併 index
WA改成 SPF + 用值當節點,但又沒處理 1:[1, 1] 回傳 True
RE加上 n == 1 的判斷,但寫在 n = len(nums) 前面
AC調整順序

正確解法
#

class Solution:
    def canTraverseAllPairs(self, nums: List[int]) -> bool:
        n = len(nums)
        if n == 1:
            return True
        if 1 in nums:
            return False                           # 1 跟誰都連不到

        m = max(nums)
        spf = list(range(m + 1))
        for i in range(2, int(m ** 0.5) + 1):
            if spf[i] == i:
                for j in range(i * i, m + 1, i):
                    if spf[j] == j:
                        spf[j] = i

        parent = list(range(m + 1))                # 節點是值

        def find(a: int) -> int:
            while parent[a] != a:
                parent[a] = parent[parent[a]]
                a = parent[a]
            return a

        for x in nums:
            v = x
            while v > 1:
                p = spf[v]
                parent[find(x)] = find(p)          # 數字跟它的質因數合併
                while v % p == 0:
                    v //= p

        root = find(nums[0])
        return all(find(x) == root for x in nums)

複雜度
#

時間 O(M log log M + n log M),M 是最大值;空間 O(M)。

要特別避免的錯誤
#

  • 兩兩算 GCD:O(n^2)。
  • 去重:兩個相同的 1 是兩個 index,去重後就變成一個了。
  • [1] 是 True,多於一個元素而且有 1 才是 False。

面試口說整理
#

任兩個 index 都能互通,就是全部在同一個連通塊。有共同因數等於有共同質因數,所以我用 SPF 篩法分解每個數,讓數字跟它的質因數在 Union-Find 裡合併,最後看所有數字是不是同一個根。1 沒有質因數要特判:只有一個元素時是 True,否則有 1 就是 False。

相關文章

LeetCode 952: Largest Component Size by Common Factor
·2 分鐘
LeetCode Hard Math Number-Theory Union-Find Hash-Table Array
LeetCode 952 解題筆記:有共同因數 ⇔ 有共同的質因數;把每個數分解質因數,同一個質因數的 index 用 Union-Find 合併,不用兩兩算 GCD
LeetCode 3618: Split Array by Prime Indices
·1 分鐘
LeetCode Medium Math Number-Theory Sieve Array
LeetCode 3618 解題筆記:判斷的是 index 是不是質數;用埃氏篩一次算出 0..n-1 哪些是質數,比每個 index 試除快
LeetCode 1979: Find Greatest Common Divisor of Array
·1 分鐘
LeetCode Easy Math Number-Theory Gcd Array
LeetCode 1979 解題筆記:找出最小值和最大值,用輾轉相除法算 GCD
LeetCode 927: Three Equal Parts
·2 分鐘
LeetCode Hard Math Array
LeetCode 927 解題筆記:三段的 1 一樣多,先數 1;第三段一定延伸到陣列尾端,它的長度決定每段要比對的內容,再檢查三段的位置不重疊
LeetCode 204: Count Primes
·1 分鐘
LeetCode Medium Array Math Enumeration Number-Theory
LeetCode 204 解題筆記:埃氏篩,只用質數 p 從 p² 開始把倍數劃掉,外層只要到 √n
LeetCode 135: Candy
·1 分鐘
LeetCode Hard Greedy Array
LeetCode 135 解題筆記:左往右掃一次滿足左鄰居、右往左掃一次滿足右鄰居,每個人取兩者較大值