127. Word Ladder && 126. Word Ladder II

127. Word Ladder

Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the word list

For example,

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["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.

 

public class Solution {
  public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
    Set<String> beginSet = new HashSet<>();
    beginSet.add(beginWord);
    Set<String> endSet = new HashSet<>();
    endSet.add(endWord);

    int ladderLen = 1;
    HashSet<String> visited = new HashSet<>(); //make sure the evolution doesn't go back
    while (!beginSet.isEmpty() && !endSet.isEmpty()) {
      //switch begin and end set for better performance
      //only expand the set with fewer elements
      if (beginSet.size() > endSet.size()) {
        Set<String> temp = beginSet;
        beginSet = endSet;
        endSet = temp;
      }

      Set<String> newBeginSet = new HashSet<>();
      for (String word : beginSet) {
        //analyze each word in beginSet
        char[] chs = word.toCharArray();
        for (int i = 0; i < chs.length; ++i) {
          char old = chs[i];
          //update each char in the word little by little, and add it to newBeginSet.
          for (char c = 'a'; c <= 'z'; ++c) {
            chs[i] = c;
            String target = String.valueOf(chs);
            if (endSet.contains(target))
              return ladderLen + 1;

            if (!visited.contains(target) && wordList.contains(target)) {
              newBeginSet.add(target);
              visited.add(target);
            }
          }
          chs[i] = old;
        }
      }

      beginSet = newBeginSet;
      ++ladderLen;
    }

    return 0;
  }
}

Graph solution, based on problem 126. Word Ladder II. But got a TLE here because doing extra work to get the path. We only need the length in this problem.

public class Solution {
  public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
    wordList.add(beginWord);
    wordList.add(endWord);
    Map<String, List<String>> neighborsMap = new HashMap<>();
    Map<String, Integer> distance = graphShortestPath(neighborsMap, beginWord, wordList);

    if (neighborsMap.get(endWord) == null)
      return 0;
    return distance.get(endWord) + 1;
  }

  //Do a breadth first search to get a Distance Map that keep the distance from the node to source
  private Map<String, Integer> graphShortestPath(Map<String, List<String>> neighborsMap, String start, Set<String> allWords) {
    Map<String, Integer> distance = new HashMap<>();
    distance.put(start, 0);
    Queue<String> unprocessed = new LinkedList<>();
    unprocessed.add(start);

    while (!unprocessed.isEmpty()) {
      String current = unprocessed.remove();
      List<String> neighbors = expand(current, allWords);
      neighborsMap.put(current, neighbors);
      int neighborDist = distance.get(current) + 1;
      for (String neighbor : neighbors) {
        if (!distance.containsKey(neighbor)) /*This neighbor is not yet visited*/ {
          distance.put(neighbor, neighborDist);
          unprocessed.add(neighbor);
        }
      }
    }
    return distance;
  }

  //return a list of words by just change one letter
  private List<String> expand(String seed, Set<String> dict) {
    List<String> expansion = new ArrayList<>();
    for (int i = 0; i < seed.length(); ++i) {
      char orig = seed.charAt(i);
      for (char ch = 'a'; ch <= 'z'; ++ch) {
        if (ch != orig) {
          String expanded = seed.substring(0, i) + ch + seed.substring(i + 1);
          if (dict.contains(expanded))
            expansion.add(expanded);
        }
      }
    }
    return expansion;
  }
}

 

126. Word Ladder II

Return the path list.

For example,

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

Return

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Array Backtracking Breadth-first Search String

Solution:
Create a graph based on all words. Connected nodes are those who have only one letter different. So the problem is to find the shortest path from StartWord to EndWord.
 
public class Solution {
  public List<List<String>> findLadders(String beginWord, String endWord, Set<String> wordList) {
    wordList.add(beginWord);
    wordList.add(endWord);
    Map<String, List<String>> neighborsMap = new HashMap<>();
    Map<String, Integer> distance = graphShortestPath(neighborsMap, beginWord, wordList);

    List<List<String>> ladders = new ArrayList<>();
    if (neighborsMap.get(endWord) == null)
      return ladders;
    getPaths(ladders, new ArrayDeque<>(), beginWord, endWord, distance, neighborsMap);
    return ladders;
  }

  //Do a breadth first search to get a Distance Map that keep the distance from the node to source
  private Map<String, Integer> graphShortestPath(Map<String, List<String>> neighborsMap, String start, Set<String> allWords) {
    Map<String, Integer> distance = new HashMap<>();
    distance.put(start, 0);
    Queue<String> unprocessed = new LinkedList<>();
    unprocessed.add(start);

    while (!unprocessed.isEmpty()) {
      String current = unprocessed.remove();
      List<String> neighbors = expand(current, allWords);
      neighborsMap.put(current, neighbors);
      int neighborDist = distance.get(current) + 1;
      for (String neighbor : neighbors) {
        if (!distance.containsKey(neighbor)) /*This neighbor is not yet visited*/ {
          distance.put(neighbor, neighborDist);
          unprocessed.add(neighbor);
        }
      }
    }
    return distance;
  }

  //DFS to get all paths
  private void getPaths(List<List<String>> ladders, Deque<String> current, String START, String end,
                        Map<String, Integer> distance, Map<String, List<String>> neighborsMap) {
    current.push(end);
    if (end.equals(START)) {
      ladders.add(new ArrayList<>(current));
      return;
    }
    for (String neighbor : neighborsMap.get(end)) {
      if (distance.get(end) == distance.get(neighbor) + 1)/*Find the parent, not just a neighbor*/ {
        getPaths(ladders, current, START, neighbor, distance, neighborsMap);
        current.pop();
      }
    }
  }

  //return a list of words by just change one letter
  private List<String> expand(String seed, Set<String> dict) {
    List<String> expansion = new ArrayList<>();
    for (int i = 0; i < seed.length(); ++i) {
      char orig = seed.charAt(i);
      for (char ch = 'a'; ch <= 'z'; ++ch) {
        if (ch != orig) {
          String expanded = seed.substring(0, i) + ch + seed.substring(i + 1);
          if (dict.contains(expanded))
            expansion.add(expanded);
        }
      }
    }
    return expansion;
  }
}

 

 

 

posted @ 2016-07-25 11:16  新一代的天皇巨星  阅读(320)  评论(0编辑  收藏  举报