📑 题目:126. 单词接龙 II

🚀 本题 LeetCode 传送门

题目大意

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

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

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

解题思路

  • 这一题是第 127 题的加强版,除了找到路径的长度,还进一步要求输出所有路径。解题思路同第 127 题一样,也是用 BFS 遍历。
  • 当前做法不是最优解,是否可以考虑双端 BFS 优化,或者迪杰斯塔拉算法?

代码

  1. package leetcode
  2. func findLadders(beginWord string, endWord string, wordList []string) [][]string {
  3. result, wordMap := make([][]string, 0), make(map[string]bool)
  4. for _, w := range wordList {
  5. wordMap[w] = true
  6. }
  7. if !wordMap[endWord] {
  8. return result
  9. }
  10. // create a queue, track the path
  11. queue := make([][]string, 0)
  12. queue = append(queue, []string{beginWord})
  13. // queueLen is used to track how many slices in queue are in the same level
  14. // if found a result, I still need to finish checking current level cause I need to return all possible paths
  15. queueLen := 1
  16. // use to track strings that this level has visited
  17. // when queueLen == 0, remove levelMap keys in wordMap
  18. levelMap := make(map[string]bool)
  19. for len(queue) > 0 {
  20. path := queue[0]
  21. queue = queue[1:]
  22. lastWord := path[len(path)-1]
  23. for i := 0; i < len(lastWord); i++ {
  24. for c := 'a'; c <= 'z'; c++ {
  25. nextWord := lastWord[:i] + string(c) + lastWord[i+1:]
  26. if nextWord == endWord {
  27. path = append(path, endWord)
  28. result = append(result, path)
  29. continue
  30. }
  31. if wordMap[nextWord] {
  32. // different from word ladder, don't remove the word from wordMap immediately
  33. // same level could reuse the key.
  34. // delete from wordMap only when currently level is done.
  35. levelMap[nextWord] = true
  36. newPath := make([]string, len(path))
  37. copy(newPath, path)
  38. newPath = append(newPath, nextWord)
  39. queue = append(queue, newPath)
  40. }
  41. }
  42. }
  43. queueLen--
  44. // if queueLen is 0, means finish traversing current level. if result is not empty, return result
  45. if queueLen == 0 {
  46. if len(result) > 0 {
  47. return result
  48. }
  49. for k := range levelMap {
  50. delete(wordMap, k)
  51. }
  52. // clear levelMap
  53. levelMap = make(map[string]bool)
  54. queueLen = len(queue)
  55. }
  56. }
  57. return result
  58. }