classSolution: defminMutation(self, start: str, end: str, bank: List[str]) -> int: if start == end: return0 bank = set(bank) if end notin bank: return -1 q = deque([(start, 0)]) while q: cur, step = q.popleft() for i, x inenumerate(cur): for y in"ACGT": if y != x: nxt = cur[:i] + y + cur[i + 1:] if nxt in bank: if nxt == end: return step + 1 bank.remove(nxt) q.append((nxt, step + 1)) return -1
funcminMutation(start, end string, bank []string)int { if start == end { return0 } bankSet := map[string]struct{}{} for _, s := range bank { bankSet[s] = struct{}{} } if _, ok := bankSet[end]; !ok { return-1 }
q := []string{start} for step := 0; q != nil; step++ { tmp := q q = nil for _, cur := range tmp { for i, x := range cur { for _, y := range"ACGT" { if y != x { nxt := cur[:i] + string(y) + cur[i+1:] if _, ok := bankSet[nxt]; ok { if nxt == end { return step + 1 } delete(bankSet, nxt) q = append(q, nxt) } } } } } } return-1 }
复杂度分析
时间复杂度:$O(C \times n \times m)$,其中 $n$ 为基因序列的长度,$m$ 为数组 bank 的长度。对于队列中的每个合法的基因序列每次都需要计算 $C \times n$ 种变化,在这里 $C = 4$;队列中最多有 $m$ 个元素,因此时间复杂度为 $O(C \times n \times m)$。
已知方法一中广度优先搜索方法,我们可以对 bank 进行预处理,只在合法的基因变化进行搜索即可。由于题目中给定的 bank 基因库的长度较小,因此可以直接在对 bank 进行预处理,找到基因库中的每个基因的合法变换,而不需要像方法一中每次都需要去计算基因的变化序列,我们将每个基因的合法变化关系存储在邻接表 adj 中,每次基因变化搜索只在 adj 中进行即可。
defdiffOne(s: str, t: str) -> bool: returnsum(x != y for x, y inzip(s, t)) == 1
m = len(bank) adj = [[] for _ inrange(m)] endIndex = -1 for i, s inenumerate(bank): if s == end: endIndex = i for j inrange(i + 1, m): if diffOne(s, bank[j]): adj[i].append(j) adj[j].append(i) if endIndex == -1: return -1
q = [i for i, s inenumerate(bank) if diffOne(start, s)] vis = set(q) step = 1 while q: tmp = q q = [] for cur in tmp: if cur == endIndex: return step for nxt in adj[cur]: if nxt notin vis: vis.add(nxt) q.append(nxt) step += 1 return -1
classSolution { public: intminMutation(string start, string end, vector<string>& bank){ int m = start.size(); int n = bank.size(); vector<vector<int>> adj(n); int endIndex = -1; for (int i = 0; i < n; i++) { if (end == bank[i]) { endIndex = i; } for (int j = i + 1; j < n; j++) { int mutations = 0; for (int k = 0; k < m; k++) { if (bank[i][k] != bank[j][k]) { mutations++; } if (mutations > 1) { break; } } if (mutations == 1) { adj[i].emplace_back(j); adj[j].emplace_back(i); } } } if (endIndex == -1) { return-1; }
queue<int> qu; vector<bool> visited(n, false); int step = 1; for (int i = 0; i < n; i++) { int mutations = 0; for (int k = 0; k < m; k++) { if (start[k] != bank[i][k]) { mutations++; } if (mutations > 1) { break; } } if (mutations == 1) { qu.emplace(i); visited[i] = true; } } while (!qu.empty()) { int sz = qu.size(); for (int i = 0; i < sz; i++) { int curr = qu.front(); qu.pop(); if (curr == endIndex) { return step; } for (auto & next : adj[curr]) { if (visited[next]) { continue; } visited[next] = true; qu.emplace(next); } } step++; } return-1; } };
publicclassSolution { publicintMinMutation(string start, string end, string[] bank) { int m = start.Length; int n = bank.Length; IList<int>[] adj = new IList<int>[n]; for (int i = 0; i < n; i++) { adj[i] = new List<int>(); } int endIndex = -1; for (int i = 0; i < n; i++) { if (end.Equals(bank[i])) { endIndex = i; } for (int j = i + 1; j < n; j++) { int mutations = 0; for (int k = 0; k < m; k++) { if (bank[i][k] != bank[j][k]) { mutations++; } if (mutations > 1) { break; } } if (mutations == 1) { adj[i].Add(j); adj[j].Add(i); } } } if (endIndex == -1) { return-1; }
Queue<int> queue = new Queue<int>(); bool[] visited = newbool[n]; int step = 1; for (int i = 0; i < n; i++) { int mutations = 0; for (int k = 0; k < m; k++) { if (start[k] != bank[i][k]) { mutations++; } if (mutations > 1) { break; } } if (mutations == 1) { queue.Enqueue(i); visited[i] = true; } } while (queue.Count > 0) { int sz = queue.Count; for (int i = 0; i < sz; i++) { int curr = queue.Dequeue(); if (curr == endIndex) { return step; } foreach (int next in adj[curr]) { if (visited[next]) { continue; } visited[next] = true; queue.Enqueue(next); } } step++; } return-1; } }
funcdiffOne(s, t string) (diff bool) { for i := range s { if s[i] != t[i] { if diff { returnfalse } diff = true } } return }
funcminMutation(start, end string, bank []string)int { if start == end { return0 }
m := len(bank) adj := make([][]int, m) endIndex := -1 for i, s := range bank { if s == end { endIndex = i } for j := i + 1; j < m; j++ { if diffOne(s, bank[j]) { adj[i] = append(adj[i], j) adj[j] = append(adj[j], i) } } } if endIndex == -1 { return-1 }
var q []int vis := make([]bool, m) for i, s := range bank { if diffOne(start, s) { q = append(q, i) vis[i] = true } } for step := 1; q != nil; step++ { tmp := q q = nil for _, cur := range tmp { if cur == endIndex { return step } for _, nxt := range adj[cur] { if !vis[nxt] { vis[nxt] = true q = append(q, nxt) } } } } return-1 }