題目描述:給定起始基因序列 startGene 和目標基因序列 endGene,以及一個合法基因庫 bank。每次突變只能改變序列中的一個字元,且改變後的序列必須存在於 bank 中。求從 startGene 變為 endGene 所需的最少突變次數;若無法到達則回傳 -1。
解題思路:本題與「單詞接龍(Word Ladder)」問題結構完全相同,是求最短路徑的問題,適合使用 BFS。
將每個基因序列視為圖中的一個節點,若兩個序列僅差一個字元且其中一個(目標序列)在 bank 中,則兩節點之間有邊相連。我們要求從 startGene 到 endGene 的最短路徑長度(邊數)。
BFS 策略:以 startGene 為起點,對當前序列的每個位置,嘗試將該位置替換為 {A, C, G, T} 四個字元之一。若替換後的新序列在 bank 集合中且尚未訪問,則加入佇列。BFS 的層數即為突變次數。
時間複雜度:O(N × L × 4) = O(N × L) — 其中 N 為 bank 的大小,L 為基因序列的長度(固定為 8)。BFS 最多訪問 N 個節點,每個節點嘗試 L × 4 種突變。
空間複雜度:O(N × L) — bankSet 和 visited 各儲存至多 N 個長度為 L 的字串;BFS 佇列大小亦為 O(N)。
1. Build bankSet from bank array for O(1) lookup
2. If endGene not in bankSet, return -1
3. Initialize BFS queue with startGene; mark startGene as visited; mutations = 0
4. While queue is not empty:
a. For each gene in current BFS level:
- Dequeue curr; if curr == endGene, return mutations
- For each position pos in curr:
* Save original = curr[pos]
* For each char c in {A, C, G, T}:
- If c == original, skip
- Set curr[pos] = c
- If curr is in bankSet and not visited: mark visited, enqueue curr
- Restore curr[pos] = original
b. Increment mutations
5. Return -1 (endGene unreachable)方法一:雙向 BFS(Bidirectional BFS)
同時從 startGene 和 endGene 開始向中間擴展,每次選擇規模較小的那一側進行擴展。當兩側的搜尋集合相交時即找到最短路徑。時間複雜度降至 O(N × L × 4^(d/2)),其中 d 為最短路徑長度,搜尋空間顯著縮小。
方法二:DFS + 剪枝(回溯法) 用 DFS 枚舉所有可能的突變路徑,記錄最短路徑長度。需要維護訪問集合避免重複,並透過當前步數剪枝。時間複雜度最壞為指數級,但由於 bank 大小很小(≤ 10),實際執行速度可接受。相較 BFS 不保證最優先找到最短路徑,需遍歷所有路徑後比較。