lintcode 单词接龙II

题意

  给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列

  比如:

    1、每次只能改变一个字母。

    2、变换过程中的中间单词必须在字典中出现。

注意事项

  • 所有单词具有相同的长度。
  • 所有单词都只包含小写字母。

样例

  给出数据如下:

  start = "hit"

  end = "cog"

  dict = ["hot","dot","dog","lot","log"]

  返回

  [

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

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

    ]

 

解题思路

  根据每两个单词是否只差一个字母,进行建图,然后如下。

  1.深搜 + 回溯 + 记忆化(记录每个节点到 终结点 的最短转换序列),超时啦。。。

  2.通过广搜 计算出终结点到各个节点的最短距离(包括源节点到终结点的最短距离,也就是和 最短转换序列的长度对应)

public class Solution {
    /**
     * @param start, a string
     * @param end,   a string
     * @param dict,  a set of string
     * @return a list of lists of string
     */
    public List<List<String>> findLadders(String start, String end, Set<String> dict) {
        // write your code here
        Map<String, List<String>> g = new HashMap<>();
        Set<String> words = new HashSet<>(dict);
        words.add(start);
        words.add(end);

        String[] wordArray = words.toArray(new String[0]);
        for (int i = 0; i < wordArray.length - 1; ++i) {
            for (int j = i + 1; j < wordArray.length; ++j) {
                String first = wordArray[i], second = wordArray[j];
                if (this.wordDiffCnt(first, second) == 1) {
                    if (!g.containsKey(first)) {
                        List<String> newList = new ArrayList<>();
                        g.put(first, newList);
                    }
                    g.get(first).add(second);

                    if (!g.containsKey(second)) {
                        List<String> newList = new ArrayList<>();
                        g.put(second, newList);
                    }
                    g.get(second).add(first);
                }
            }
        }

        resultMap = new HashMap<>();
        visit = new HashSet<>();

//      return dfs(g, start, end);//超时了,不知道怎么优化

        List<List<String>> result = new ArrayList<>();
        dist = new HashMap<>();
        dfs(result, new LinkedList<String>(), g, start, end, bfs(g, end, start));
        return result;
    }

    //通过bfs计算 终结点 到 源结点 的最短转换长度,以及 终结点到各个结点的最短距离(在通过 dfs寻找 最短转换序列的时候用到)
    private Map<String, Integer> dist;
    private int bfs(Map<String, List<String>> g, String start, String end) {
        Queue<String> queue = new LinkedList<>();
        visit.add(start);
        queue.add(start);
        dist.put(start, 1);
        int minLen = 0;
        while(!queue.isEmpty()) {
            start = queue.poll();

            if(start.equals(end)) {
                if(minLen == 0) {
                    minLen = dist.get(start);
                }
            }

            if(g.containsKey(start)) {
                for (String next : g.get(start)) {
                    if(visit.contains(next)) continue;
                    visit.add(next);
                    queue.add(next);
                    dist.put(next, dist.get(start)+1);
                }
            }
        }
        visit.clear();
        return minLen;
    }

    private void dfs(List<List<String>> result, List<String> tmp, Map<String, List<String>> g, String start, String end, int minLen) {

        if(tmp.size()+dist.get(start)-1 >= minLen) return;

        if (start.equals(end)) {
            result.add(new ArrayList<>(tmp));
            result.get(result.size() - 1).add(end);
            return;
        }

        visit.add(start);
        tmp.add(start);
        if (g.containsKey(start)) {
            for (String next : g.get(start)) {
                if(visit.contains(next)) continue;
                dfs(result, tmp, g, next, end, minLen);
            }
        }
        visit.remove(start);
        tmp.remove(tmp.size()-1);
    }

    @Deprecated
    private List<List<String>> dfs(Map<String, List<String>> g, String start, String end) {
        List<List<String>> result = new ArrayList<>();
        if (start.equals(end)) {
            List<String> list = new ArrayList<>();
            list.add(end);
            result.add(list);
            resultMap.put(end, result);
            return result;
        }

        if (resultMap.containsKey(start)) {
            return resultMap.get(start);
        }

        if (!g.containsKey(start)) {
            resultMap.put(start, null);
            return null;
        }

        visit.add(start);

        List<List<String>> nextResult = new ArrayList<>();

        int minLen = Integer.MAX_VALUE;
        for (String next : g.get(start)) {
            if(visit.contains(next)) continue;
            List<List<String>> tmp = dfs(g, next, end);
            if (tmp != null) {
                for (List<String> list : tmp) {
                    if(minLen > list.size()) minLen = list.size();
                    nextResult.add(list);
                }
            }
        }

        visit.remove(start);

        for (List<String> list : nextResult) {
            if (list.size() == minLen) {
                List<String> tmp = new LinkedList<>(list);
                tmp.add(0, start);
                result.add(tmp);
            }
        }
        if(result.size() > 0) {
            resultMap.put(start, result);
        }
        return result;
    }

    //记忆化搜索 每个节点到终点的最小步数的路径
    private Map<String, List<List<String>>> resultMap;
    //每个节点的访问的情况
    private Set<String> visit;

    private int wordDiffCnt(String s1, String s2) {
        int diffCnt = 0;
        for (int i = 0; i < s1.length(); ++i) {
            if (s1.charAt(i) != s2.charAt(i)) {
                ++diffCnt;
            }
        }
        return diffCnt;
    }
}

 

 

 

posted @ 2017-08-09 19:10  hjzqyx  阅读(835)  评论(0编辑  收藏  举报