• LeetCode每日一题(126. Word Ladder II)


    A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> … -> sk such that:

    Every adjacent pair of words differs by a single letter.
    Every si for 1 <= i <= k is in wordList. Note that beginWord does not need to be in wordList.
    sk == endWord
    Given two words, beginWord and endWord, and a dictionary wordList, return all the shortest transformation sequences from beginWord to endWord, or an empty list if no such sequence exists. Each sequence should be returned as a list of the words [beginWord, s1, s2, …, sk].

    Example 1:

    Input: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
    Output: [[“hit”,“hot”,“dot”,“dog”,“cog”],[“hit”,“hot”,“lot”,“log”,“cog”]]

    Explanation: There are 2 shortest transformation sequences:
    “hit” -> “hot” -> “dot” -> “dog” -> “cog”
    “hit” -> “hot” -> “lot” -> “log” -> “cog”

    Example 2:

    Input: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
    Output: []

    Explanation: The endWord “cog” is not in wordList, therefore there is no valid transformation sequence.

    Constraints:

    • 1 <= beginWord.length <= 5
    • endWord.length == beginWord.length
    • 1 <= wordList.length <= 500
    • wordList[i].length == beginWord.length
    • beginWord, endWord, and wordList[i] consist of lowercase English letters.
    • beginWord != endWord
    • All the words in wordList are unique.

    这题以前做过,但是以前的答案现在再提交结果变成了超时。于是重新做一遍。大体思路是先正向找最短路径,然后再反向把这些路径收集起来。在查找下一跳的字符串时, 我们枚举出所有的可能的变化(只有一个字符差异)。标记出所有的最短路径后,我们开始反向收集那些最终能到达 end_word 的路径,之所以采用反向,是因为这样我们不用去处理那些路径最终到不了 end_word 的情况。假设我们找到的最短路径中,从 begin_word 到 end_word 的最短步数是 n, 我们从 end_word 开始查找步数为 n-1 且与 end_word 相差一个字符的单词, 然后以这些单词为基础再查找 n-2, 与这些单词相差一个字符的单词,如此递归直到 n=1 的情况。


    
    use std::collections::HashMap;
    
    impl Solution {
        fn is_exact_one_diff(word1: &str, word2: &str) -> bool {
            let mut count = 0;
            for (c1, c2) in word1.chars().zip(word2.chars()) {
                if c1 != c2 {
                    count += 1;
                }
            }
            count == 1
        }
        fn extract_path(
            steps: &HashMap<i32, Vec<String>>,
            end_word: &str,
            curr: i32,
        ) -> Vec<Vec<String>> {
            if curr == 1 {
                return vec![vec![end_word.to_owned()]];
            }
            let mut ans = Vec::new();
            let nexts = steps.get(&(curr - 1)).unwrap();
            for next in nexts {
                if Solution::is_exact_one_diff(next, end_word) {
                    let mut paths = Solution::extract_path(steps, next, curr - 1);
                    for p in &mut paths {
                        p.push(end_word.to_owned());
                    }
                    ans.append(&mut paths);
                }
            }
            ans
        }
    
        fn gen_morph(word: String, steps: &HashMap<String, i32>) -> Vec<String> {
            let lowers: Vec<char> = "abcdefghijklmnopqrstuvwxyz".chars().map(|c| c).collect();
            let mut res = Vec::new();
            let mut chars: Vec<char> = word.chars().collect();
            for i in 0..chars.len() {
                let c = chars[i];
                for l in &lowers {
                    if c != *l {
                        chars[i] = *l;
                        let w: String = chars.iter().collect();
                        if steps.contains_key(&w) {
                            res.push(w);
                        }
                    }
                }
                chars[i] = c;
            }
            res
        }
        pub fn find_ladders(
            begin_word: String,
            end_word: String,
            word_list: Vec<String>,
        ) -> Vec<Vec<String>> {
            let mut word_steps: HashMap<String, i32> =
                word_list.into_iter().map(|w| (w, i32::MAX)).collect();
            let mut stack = vec![begin_word.clone()];
            let mut curr = 1;
            loop {
                let mut next_stack = Vec::new();
                while let Some(w) = stack.pop() {
                    for morph in Solution::gen_morph(w, &word_steps) {
                        if let Some(step) = word_steps.get_mut(&morph) {
                            if *step > curr {
                                next_stack.push(morph);
                                *step = curr;
                            }
                        }
                    }
                }
                if next_stack.is_empty() {
                    break;
                }
                stack = next_stack;
                curr += 1;
            }
            if !word_steps.contains_key(&end_word) {
                return vec![];
            }
            let final_step = *word_steps.get(&end_word).unwrap();
            if final_step == i32::MAX {
                return vec![];
            }
            let steps = word_steps
                .into_iter()
                .fold(HashMap::new(), |mut m, (w, c)| {
                    m.entry(c).or_insert(Vec::new()).push(w);
                    m
                });
            let mut paths = Solution::extract_path(&steps, &end_word, final_step);
            for p in &mut paths {
                p.insert(0, begin_word.clone());
            }
            paths
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
  • 相关阅读:
    JS数组和字符串的原生方法
    记某信漏洞复现
    基于云边协同架构的五大应用场景革新
    Qt多工程同名字段自动翻译工具
    MySQL主从
    纯代码方式杀死指定进程名的进程(Linux&Windows)
    Golang的GC
    Android 13.0 系统go版添加支持AppWidget小部件功能的实现
    Python爱心代码
    选择HAL库还是标准库
  • 原文地址:https://blog.csdn.net/wangjun861205/article/details/126331198