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

LeetCode 1998: GCD Sort of an Array

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

基本資料
#

難易度: hard 第一次嘗試:2026-10-12

  • 提交紀錄:AC → RE → WA → AC → WA ×2 → AC ×2(同一天練了三種篩法)

解題思路
#

可以交換兩個有共同因數的數。在同一個連通塊裡,透過一連串交換,任意排列都做得到(跟「可以交換的位置形成連通塊,塊內可以任意排序」一樣)。

所以:

  1. 用 Union-Find 把每個數字跟它的質因數合併(跟 LeetCode 2709 一樣,節點是值)。
  2. 排序後,第 i 個位置原本的數 nums[i] 和排好後的數 sorted[i] 必須在同一個連通塊,不然沒辦法換過來。

我的嘗試
#

第一次用「試除 + owner[p]、節點是 index」AC,之後想練 SPF 篩法:

版本問題
RE變數名稱打錯(sorted_unms)
WASPF 篩法寫成 spf[i] = i,應該是 spf[j] = i,合數的 SPF 一直是自己;分解時又直接改 num,之後拿去 union 的值也不對。例如 [9, 3]:9 和 3 有共同因數 3,可以交換排好,答案是 True,回傳 False
AC修好兩個地方
兩次 WA改用線性篩,但內層迴圈放在 if spf[i] == 0(是質數)裡面,只有質數會去劃掉倍數,像 8 = 4 × 2 就沒人處理,被當成質數。例如 [8, 2]:答案是 True,回傳 False
AC ×2內層迴圈移到外面,每個 i 都要跑

正確解法
#

class Solution:
    def gcdSort(self, nums: List[int]) -> bool:
        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                 # 是 spf[j]

        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                                  # 用副本分解,x 留著 union
            while v > 1:
                p = spf[v]
                parent[find(x)] = find(p)
                while v % p == 0:
                    v //= p

        return all(find(a) == find(b) for a, b in zip(nums, sorted(nums)))

複雜度
#

時間 O(M log log M + n log M + n log n),空間 O(M)。

要特別避免的錯誤
#

  • SPF 篩法裡寫成 spf[i]。
  • 分解質因數時改到原本的變數,之後 union 用的值就錯了。
  • 線性篩的內層迴圈要對每個 i 跑。

面試口說整理
#

同一個連通塊裡的數可以透過交換任意排列,所以我用 SPF 篩法把每個數跟它的質因數在 Union-Find 裡合併,再把陣列排序,檢查每個位置原本的數和排序後的數是不是在同一組。時間 O(M log log M + n log n)。

相關文章

LeetCode 2709: Greatest Common Divisor Traversal
·2 分鐘
LeetCode Hard Math Number-Theory Union-Find Sieve Gcd Array
LeetCode 2709 解題筆記:任兩個 index 都能互通 ⇔ 全部在同一個連通塊;用 SPF 分解質因數,數字跟它的質因數在 Union-Find 裡合併;1 要特別處理
LeetCode 1627: Graph Connectivity With Threshold
·1 分鐘
LeetCode Hard Math Number-Theory Union-Find Array
LeetCode 1627 解題筆記:不用兩兩算 GCD;對每個 z > threshold,把 z 的所有倍數連起來,總共 O(n log n) 次合併
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 2523: Closest Prime Numbers in Range
·1 分鐘
LeetCode Medium Math Number-Theory Sieve Array
LeetCode 2523 解題筆記:篩出範圍內的質數,相鄰的兩個質數才可能是最接近的;也可以從 left 往右試除,找到差是 2 的雙生質數就停
LeetCode 2761: Prime Pairs With Target Sum
·1 分鐘
LeetCode Medium Math Number-Theory Sieve Enumeration Array
LeetCode 2761 解題筆記:篩出 < n 的質數,x 從小到大、只看到 n / 2,x 和 n - x 都是質數就是一對
LeetCode 3618: Split Array by Prime Indices
·1 分鐘
LeetCode Medium Math Number-Theory Sieve Array
LeetCode 3618 解題筆記:判斷的是 index 是不是質數;用埃氏篩一次算出 0..n-1 哪些是質數,比每個 index 試除快