Saturday, January 10, 2015

LeetCode 126: Word Ladder II

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

Return

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

  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
// Algorithm is correct but exceeds time limit.
public class Solution {
    private List<List<String>> result;
    private List<String> reversedPath;
    private Map<String, List<String>> map;
    private int shortLen;
    
    public List<List<String>> findLadders(String start, String end, Set<String> dict) {
        // Adopt breath first search
        result = new LinkedList<>();
        reversedPath = new LinkedList<>();
        map = new HashMap<>();
        shortLen = Integer.MAX_VALUE;
        
        bfs(start, end, dict);
        
        if (shortLen == Integer.MAX_VALUE)
            return result;
        
        reversedPath.add(end);
        backTracking(end, 1);
        
        return result;
    }
    
    private void backTracking(String end, int cnt)
    {
        if (cnt == shortLen)
        {
            List<String> path = new LinkedList<>();

            for (int i = reversedPath.size()-1; i >= 0; i--)
                path.add(reversedPath.get(i));

            if (!result.contains(path))    
                result.add(path);
        }
        else
        {
            for (String str : map.get(end))
            {
                reversedPath.add(str);
                backTracking(str, cnt+1);
                reversedPath.remove(reversedPath.size()-1);
            }
        }
    }
    
    private void bfs(String start, String end, Set<String> dict)
    {
        Queue<String> word = new LinkedList<>();
        Queue<Integer> length = new LinkedList<>();
        
        word.offer(start);
        length.offer(2);
        
        while (!word.isEmpty())
        {
            String v = word.poll();
            int len = length.poll();
            
            if (len > shortLen)
                return;

            for (int i = 0; i < v.length(); i++)
            {
                // Note: Adopt character replacement strategy can save much time.
                for (char c = 'a'; c <= 'z'; c++)
                {
                    if (v.charAt(i) == c)
                        continue;
                        
                    String w = replace(v, i, c);
                    
                    if (map.containsKey(v) && map.get(v).contains(w))
                        continue;
                    
                    if (w.equals(end))
                    {
                        shortLen = len;
                        
                        if (!map.containsKey(end))
                        {
                            List<String> parent = new LinkedList<>();
                            parent.add(v);
                            map.put(end, parent);
                        }
                        else
                            map.get(end).add(v);
                    }
                    
                    if (dict.contains(w))
                    {                        
                        if (!map.containsKey(w))
                        {
                            List<String> parent = new LinkedList<>();
                            parent.add(v);
                            map.put(w, parent);
                        }
                        else
                            map.get(w).add(v);
                        
                        word.offer(w);
                        length.offer(len+1);
                    }
                }
            }
        }
    }
    
    private String replace(String s, int index, char c)
    {
        char[] chars = s.toCharArray();
        chars[index] = c;
        return new String(chars);
    }
}

No comments:

Post a Comment