lc

    技术2023-10-18  82

    题目:单词接龙 II hard

    给定两个单词(beginWord 和 endWord)和一个字典 wordList, 找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:     每次转换只能改变一个字母。     转换后得到的单词必须是字典中的单词。

    说明:     如果不存在这样的转换序列,返回一个空列表。     所有单词具有相同的长度。     所有单词只由小写字母组成。     字典中不存在重复的单词。     你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

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

    输出: [   ["hit","hot","dot","dog","cog"],   ["hit","hot","lot","log","cog"] ]

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

    输出: [] 解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。

     

    package leetCode.BFS; import java.util.*; public class lc_bfs_126_findLadders { /* 思路: 1.dfs 超时 2.bfs 直接记录路径path,visited用来记录除了当前访问层外,所有的已经访问过的单词, subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词 */ /** * bfs * 直接记录路径path,visited用来记录除了当前访问层外,所有的已经访问过的单词, * subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词 */ public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { ArrayDeque<List<String>> pathsQue = new ArrayDeque<>(); LinkedList<String> path = new LinkedList<>(); List<List<String>> ans = new LinkedList<>(); int indexOfendword = wordList.indexOf(endWord); if (indexOfendword == -1) {//没有就直接返回,不用查找了 return ans; } path.add(beginWord); pathsQue.offer(path); HashSet<String> dict = new HashSet<>(wordList); //用来记录除了当前访问层外,所有的已经访问过的单词, // subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词 HashSet<String> visited = new HashSet<>(); visited.add(beginWord); boolean isFound = false;//用来标记在该层已经找到结束单词,不要再遍历下一层了 while (!pathsQue.isEmpty()) { HashSet<String> subVisited = new HashSet<>(); int size = pathsQue.size(); for (int j = 0; j < size; j++) { List<String> curPath = pathsQue.poll(); //得到当前路径的末尾单词 String lastWord = curPath.get(curPath.size() - 1); if (lastWord.equals(endWord)) { isFound = true; ans.add(curPath); continue;//不要再扩展路径了,直接检查下一个,该层遍历完就结束 } // 一次性得到所有的下一个的节点 List<String> neighbors = getNeighbor(lastWord, dict); for (String n : neighbors) { //只考虑之前没有出现过的单词,前面层已经出现过的单词再次加入肯定不是最短的,剪枝了 if (!visited.contains(n)) { //加入当前单词 LinkedList<String> newPath = new LinkedList<>(curPath); newPath.add(n); pathsQue.offer(newPath); //加入当前访问层的已访问的单词,里面的元素和visited里的都不重复 subVisited.add(n); } } }//该层遍历完 visited.addAll(subVisited);//将当前层的已访问单词加入总的已访问单词 if (isFound) break;//找到后,当前层访问完就不要进行下一层循环,直接跳出返回 } return ans; } // 得到node结点的所有的下一个节点集合 public List<String> getNeighbor(String node, Set<String> dict) { ArrayList<String> res = new ArrayList<String>(); char chs[] = node.toCharArray(); for (char ch = 'a'; ch <= 'z'; ch++) { for (int i = 0; i < chs.length; i++) { if (chs[i] == ch) continue; char old_ch = chs[i]; chs[i] = ch; if (dict.contains(String.valueOf(chs))) { res.add(String.valueOf(chs)); } chs[i] = old_ch; } } return res; } /** * 超时 dfs版本 */ int minLen = Integer.MAX_VALUE; public List<List<String>> findLadders2(String beginWord, String endWord, List<String> wordList) { ArrayList<List<String>> ans = new ArrayList<>(); boolean[] vis = new boolean[wordList.size()]; ArrayList<String> path = new ArrayList<>(); path.add(beginWord); dfs(beginWord, path, ans, vis, endWord, wordList); return ans; } public void dfs(String cur, List<String> path, List<List<String>> ans, boolean[] vis, String endWord, List<String> wordList) { if (cur.equals(endWord)) { if (path.size() <= minLen) { if (path.size() < minLen) // ans = new ArrayList<>(); ans.clear(); ans.add(new ArrayList<>(path)); minLen = path.size(); } return; } if (path.size() >= minLen) { return; } for (int i = 0; i < wordList.size(); i++) { String word = wordList.get(i); if (!vis[i] && isLike(cur, word)) { vis[i] = true; path.add(word); dfs(word, path, ans, vis, endWord, wordList); path.remove(path.size() - 1); vis[i] = false; } } } public boolean isLike(String a, String b) { int count = 0; for (int i = 0; i < a.length(); i++) { if (a.charAt(i) != b.charAt(i)) { count++; if (count > 1) return false; } } return true; } }

     

    Processed: 0.019, SQL: 9