266, 单词接龙

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

    1,每次转换只能改变一个字母。

    2,转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。

  • 所有单词具有相同的长度。

  • 所有单词只由小写字母组成。

  • 字典中不存在重复的单词。

  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
返回他的长度 5.

 

 

示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。

答案:

 1public int ladderLength1(String beginWord, String endWord, List<String> wordList) {
2    Set<String> dict = new HashSet<>(wordList);
3    Set<String> vis = new HashSet<>();
4    Queue<String> q = new LinkedList<>();
5    q.add(beginWord);
6    int len = 1;
7    while (!q.isEmpty()) {
8        for (int i = q.size(); i > 0; i--) {
9            String w = q.poll();
10            if (w.equals(endWord))
11                return len;
12            for (int j = 0; j < w.length(); j++) {
13                char[] ch = w.toCharArray();
14                for (char c = 'a'; c <= 'z'; c++) {
15                    if (c == w.charAt(j))
16                        continue;
17                    ch[j] = c;
18                    String nb = String.valueOf(ch);
19                    if (dict.contains(nb) && vis.add(nb))
20                        q.add(nb);
21                }
22            }
23        }
24        len++;
25    }
26    return 0;
27}

解析:

如果熟悉bfs的同学,估计对这些代码理解起来会更容易一些。disc是字典集合,vis主要是判断集合disc中的元素是否被访问过。其中第17行会改变单词中的一个字符,然后在19行在判断这个单词是否是在字典中,并且是否被访问过,如果字典中有并且没有被访问过,那么就加入到队列q中。注意这里的第8行是不能去掉的,因为第20行加入q中的都是只改变一个字符的单词,只相当于转换了一次。下面来看一种递归的解法

 1public int ladderLength(String beginWord, String endWord, List<String> wordList) {
2    if (wordList == null || wordList.size() == 0)
3        return 0;
4    HashSet<String> start = new HashSet<>();
5    HashSet<String> dic = new HashSet<>(wordList);
6    start.add(beginWord);
7    if (!dic.contains(endWord))
8        return 0;
9    return bfs(start, endWord, dic, 2);
10
11}
12
13public int bfs(HashSet<String> start, String end, HashSet<String> dic, int len) {
14    if (start.size() == 0)
15        return 0;
16    dic.removeAll(start);
17    HashSet<String> next = new HashSet<>();
18    for (String s : start) {
19        char[] arr = s.toCharArray();
20        for (int i = 0; i < arr.length; i++) {
21            char tmp = arr[i];
22            for (char c = 'a'; c <= 'z'; c++) {
23                if (tmp == c)
24                    continue;
25                arr[i] = c;
26                String nstr = new String(arr);
27                if (dic.contains(nstr)) {
28                    if (end.equals(nstr))
29                        return len;
30                    else
31                        next.add(nstr);
32                }
33            }
34            arr[i] = tmp;
35        }
36    }
37    return bfs(next, end, dic, len + 1);
38}

其实原理都差不多,每递归一次,len就加1。第14行如果条件成立,说明查找的时候出现了断裂,直接返回0即可。我们先看一下13行的start,再看37行的递归,发现start就是递归的时候传递的next,而next是在17行初始化的,只有执行到31行才会有值。其实第17行到36行代码和上面那种方法差不多。第16行是去掉重复的。

 

上一篇:angular的formGroup的校验触发


下一篇:react material UI开发环境,table 的中每列限制长度