返回介绍

solution / 0400-0499 / 0433.Minimum Genetic Mutation / README

发布于 2024-06-17 01:04:00 字数 9803 浏览 0 评论 0 收藏 0

433. 最小基因变化

English Version

题目描述

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A''C''G''T' 之一。

假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。

  • 例如,"AACCGGTT" --> "AACCGGTA" 就是一次基因变化。

另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。(变化后的基因必须位于基因库 bank 中)

给你两个基因序列 startend ,以及一个基因库 bank ,请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化,返回 -1

注意:起始基因序列 start 默认是有效的,但是它并不一定会出现在基因库中。

 

示例 1:

输入:start = "AACCGGTT", end = "AACCGGTA", bank = ["AACCGGTA"]
输出:1

示例 2:

输入:start = "AACCGGTT", end = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]
输出:2

示例 3:

输入:start = "AAAAACCC", end = "AACCCCCC", bank = ["AAAACCCC","AAACCCCC","AACCCCCC"]
输出:3

 

提示:

  • start.length == 8
  • end.length == 8
  • 0 <= bank.length <= 10
  • bank[i].length == 8
  • startendbank[i] 仅由字符 ['A', 'C', 'G', 'T'] 组成

解法

方法一:BFS

class Solution:
  def minMutation(self, start: str, end: str, bank: List[str]) -> int:
    s = set(bank)
    q = deque([(start, 0)])
    mp = {'A': 'TCG', 'T': 'ACG', 'C': 'ATG', 'G': 'ATC'}
    while q:
      t, step = q.popleft()
      if t == end:
        return step
      for i, v in enumerate(t):
        for j in mp[v]:
          next = t[:i] + j + t[i + 1 :]
          if next in s:
            q.append((next, step + 1))
            s.remove(next)
    return -1
class Solution {
  public int minMutation(String start, String end, String[] bank) {
    Set<String> s = new HashSet<>();
    for (String b : bank) {
      s.add(b);
    }
    Map<Character, String> mp = new HashMap<>(4);
    mp.put('A', "TCG");
    mp.put('T', "ACG");
    mp.put('C', "ATG");
    mp.put('G', "ATC");
    Deque<Pair<String, Integer>> q = new LinkedList<>();
    q.offer(new Pair<>(start, 0));
    while (!q.isEmpty()) {
      Pair<String, Integer> p = q.poll();
      String t = p.getKey();
      int step = p.getValue();
      if (end.equals(t)) {
        return step;
      }
      for (int i = 0; i < t.length(); ++i) {
        for (char c : mp.get(t.charAt(i)).toCharArray()) {
          String next = t.substring(0, i) + c + t.substring(i + 1);
          if (s.contains(next)) {
            q.offer(new Pair<>(next, step + 1));
            s.remove(next);
          }
        }
      }
    }
    return -1;
  }
}
class Solution {
public:
  int minMutation(string start, string end, vector<string>& bank) {
    unordered_set<string> s;
    for (auto& b : bank) s.insert(b);
    unordered_map<char, string> mp;
    mp['A'] = "TCG";
    mp['T'] = "ACG";
    mp['C'] = "ATG";
    mp['G'] = "ATC";
    queue<pair<string, int>> q;
    q.push({start, 0});
    while (!q.empty()) {
      auto p = q.front();
      q.pop();
      string t = p.first;
      int step = p.second;
      if (t == end) return step;
      for (int i = 0; i < t.size(); ++i) {
        for (char c : mp[t[i]]) {
          string next = t.substr(0, i) + c + t.substr(i + 1, t.size() - i - 1);
          if (s.count(next)) {
            q.push({next, step + 1});
            s.erase(next);
          }
        }
      }
    }
    return -1;
  }
};
func minMutation(start string, end string, bank []string) int {
  s := make(map[string]bool)
  for _, b := range bank {
    s[b] = true
  }
  mp := make(map[byte]string)
  mp['A'] = "TCG"
  mp['T'] = "ACG"
  mp['C'] = "ATG"
  mp['G'] = "ATC"
  type pair struct {
    first  string
    second int
  }
  q := []pair{{start, 0}}
  for len(q) > 0 {
    p := q[0]
    q = q[1:]
    t, step := p.first, p.second
    if t == end {
      return step
    }
    for i := 0; i < len(t); i++ {
      for _, c := range mp[t[i]] {
        next := t[:i] + string(c) + t[i+1:]
        if s[next] {
          q = append(q, pair{next, step + 1})
          s[next] = false
        }
      }
    }
  }
  return -1
}
function minMutation(start: string, end: string, bank: string[]): number {
  const queue = [start];
  let res = 0;
  while (queue.length !== 0) {
    const n = queue.length;
    for (let i = 0; i < n; i++) {
      const s1 = queue.shift();
      if (s1 === end) {
        return res;
      }

      for (let j = bank.length - 1; j >= 0; j--) {
        const s2 = bank[j];
        let count = 0;
        for (let k = 0; k < 8; k++) {
          if (s1[k] !== s2[k]) {
            count++;
          }
        }
        if (count <= 1) {
          queue.push(...bank.splice(j, 1));
        }
      }
    }
    res++;
  }
  return -1;
}
use std::collections::VecDeque;
impl Solution {
  pub fn min_mutation(start: String, end: String, mut bank: Vec<String>) -> i32 {
    let mut queue = vec![start].into_iter().collect::<VecDeque<String>>();
    let mut res = 0;
    while !queue.is_empty() {
      let n = queue.len();
      for _ in 0..n {
        let s1 = queue.pop_front().unwrap();
        if s1 == end {
          return res;
        }

        for i in (0..bank.len()).rev() {
          let s1 = s1.as_bytes();
          let s2 = bank[i].as_bytes();
          let mut count = 0;
          for j in 0..8 {
            if s1[j] != s2[j] {
              count += 1;
            }
          }
          if count <= 1 {
            queue.push_back(bank.remove(i));
          }
        }
      }
      res += 1;
    }
    -1
  }
}

方法二:DFS

class Solution:
  def minMutation(self, start: str, end: str, bank: List[str]) -> int:
    def dfs(start, t):
      if start == end:
        nonlocal ans
        ans = min(ans, t)
        return
      for i, x in enumerate(start):
        for y in 'ACGT':
          if x != y:
            nxt = start[:i] + y + start[i + 1 :]
            if nxt in s:
              s.remove(nxt)
              dfs(nxt, t + 1)

    s = set(bank)
    ans = inf
    dfs(start, 0)
    return -1 if ans == inf else ans
class Solution {
  private int ans;
  private Set<String> s;
  private static final char[] seq = {'A', 'C', 'G', 'T'};

  public int minMutation(String start, String end, String[] bank) {
    s = new HashSet<>();
    for (String b : bank) {
      s.add(b);
    }
    ans = Integer.MAX_VALUE;
    dfs(start, end, 0);
    s.remove(start);
    return ans == Integer.MAX_VALUE ? -1 : ans;
  }

  private void dfs(String start, String end, int t) {
    if (start.equals(end)) {
      ans = Math.min(ans, t);
      return;
    }
    for (int i = 0; i < start.length(); ++i) {
      for (char c : seq) {
        if (start.charAt(i) == c) {
          continue;
        }
        String nxt = start.substring(0, i) + c + start.substring(i + 1);
        if (s.contains(nxt)) {
          s.remove(nxt);
          dfs(nxt, end, t + 1);
        }
      }
    }
  }
}
class Solution {
public:
  int ans;
  string seq = "ACGT";

  int minMutation(string start, string end, vector<string>& bank) {
    unordered_set<string> s;
    for (auto& b : bank) s.insert(b);
    ans = INT_MAX;
    s.erase(start);
    dfs(start, end, s, 0);
    return ans == INT_MAX ? -1 : ans;
  }

  void dfs(string& start, string& end, unordered_set<string>& s, int t) {
    if (start == end) {
      ans = min(ans, t);
      return;
    }
    for (int i = 0; i < start.size(); ++i) {
      for (char& c : seq) {
        if (start[i] == c) continue;
        string nxt = start.substr(0, i) + c + start.substr(i + 1, start.size() - i - 1);
        if (s.count(nxt)) {
          s.erase(nxt);
          dfs(nxt, end, s, t + 1);
        }
      }
    }
  }
};
func minMutation(start string, end string, bank []string) int {
  s := make(map[string]bool)
  for _, b := range bank {
    s[b] = true
  }
  ans := math.MaxInt32
  s[start] = false
  seq := []rune{'A', 'C', 'G', 'T'}
  var dfs func(start string, t int)
  dfs = func(start string, t int) {
    if start == end {
      if ans > t {
        ans = t
      }
      return
    }
    for i, x := range start {
      for _, y := range seq {
        if x == y {
          continue
        }
        nxt := start[:i] + string(y) + start[i+1:]
        if s[nxt] {
          s[nxt] = false
          dfs(nxt, t+1)
        }
      }
    }
  }
  dfs(start, 0)
  if ans == math.MaxInt32 {
    return -1
  }
  return ans
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文