Word Ladder

描述

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

  • Only one letter can be changed at a time
  • Each intermediate word must exist in the dictionary
    For example, Given:
  1. start = "hit"
  2. end = "cog"
  3. dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5.

Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

    分析

求最短路径,用广搜。

单队列

  1. // Word Ladder
  2. // 时间复杂度O(n),空间复杂度O(n)
  3. public class Solution {
  4. public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
  5. Queue<State> q = new LinkedList<>();
  6. HashSet<State> visited = new HashSet<>(); // 判重
  7. final Function<State, Boolean> stateIsValid = (State s) ->
  8. wordList.contains(s.word) || s.word.equals(endWord);
  9. final Function<State, Boolean> stateIsTarget = (State s) ->
  10. s.word.equals(endWord);
  11. final Function<State, HashSet<State> > stateExtend = (State s) -> {
  12. HashSet<State> result = new HashSet<>();
  13. char[] array = s.word.toCharArray();
  14. for (int i = 0; i < array.length; ++i) {
  15. final char old = array[i];
  16. for (char c = 'a'; c <= 'z'; c++) {
  17. // 防止同字母替换
  18. if (c == array[i]) continue;
  19. array[i] = c;
  20. State newState = new State(new String(array), s.level+1);
  21. if (stateIsValid.apply(newState) &&
  22. !visited.contains(newState)) {
  23. result.add(newState);
  24. }
  25. array[i] = old; // 恢复该单词
  26. }
  27. }
  28. return result;
  29. };
  30. State startState = new State(beginWord, 0);
  31. q.offer(startState);
  32. visited.add(startState);
  33. while (!q.isEmpty()) {
  34. State state = q.poll();
  35. if (stateIsTarget.apply(state)) {
  36. return state.level + 1;
  37. }
  38. HashSet<State> newStates = stateExtend.apply(state);
  39. for (State newState : newStates) {
  40. q.offer(newState);
  41. visited.add(newState);
  42. }
  43. }
  44. return 0;
  45. }
  46. static class State {
  47. String word;
  48. int level;
  49. public State(String word, int level) {
  50. this.word = word;
  51. this.level = level;
  52. }
  53. @Override
  54. public int hashCode() {
  55. return word.hashCode();
  56. }
  57. @Override
  58. public boolean equals(Object other) {
  59. if (this == other) return true;
  60. if (this.hashCode() != other.hashCode()) return false;
  61. if (!(other instanceof State)) return false;
  62. return this.word.equals(((State) other).word);
  63. }
  64. }
  65. }

双队列

  1. // Word Ladder
  2. // 时间复杂度O(n),空间复杂度O(n)
  3. public class Solution {
  4. public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
  5. Queue<String> current = new LinkedList<>(); // 当前层
  6. Queue<String> next = new LinkedList<>(); // 下一层
  7. HashSet<String> visited = new HashSet<>(); // 判重
  8. int level = -1; // 层次
  9. final Function<String, Boolean> stateIsValid = (String s) ->
  10. wordList.contains(s) || s.equals(endWord);
  11. final Function<String, Boolean> stateIsTarget = (String s) ->
  12. s.equals(endWord);
  13. final Function<String, HashSet<String> > stateExtend = (String s) -> {
  14. HashSet<String> result = new HashSet<>();
  15. char[] array = s.toCharArray();
  16. for (int i = 0; i < array.length; ++i) {
  17. final char old = array[i];
  18. for (char c = 'a'; c <= 'z'; c++) {
  19. // 防止同字母替换
  20. if (c == array[i]) continue;
  21. array[i] = c;
  22. String newState = new String(array);
  23. if (stateIsValid.apply(newState) &&
  24. !visited.contains(newState)) {
  25. result.add(newState);
  26. }
  27. array[i] = old; // 恢复该单词
  28. }
  29. }
  30. return result;
  31. };
  32. current.offer(beginWord);
  33. visited.add(beginWord);
  34. while (!current.isEmpty()) {
  35. ++level;
  36. while (!current.isEmpty()) {
  37. // 千万不能用 const auto&,pop() 会删除元素,
  38. // 引用就变成了悬空引用
  39. String state = current.poll();
  40. if (stateIsTarget.apply(state)) {
  41. return level + 1;
  42. }
  43. HashSet<String> newStates = stateExtend.apply(state);
  44. for (String newState : newStates) {
  45. next.offer(newState);
  46. visited.add(newState);
  47. }
  48. }
  49. // swap
  50. Queue<String> tmp = current;
  51. current = next;
  52. next = tmp;
  53. }
  54. return 0;
  55. }
  56. }

相关题目

原文: https://soulmachine.gitbooks.io/algorithm-essentials/content/java/bfs/word-ladder.html