zoukankan      html  css  js  c++  java
  • [LeetCode-JAVA] 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"]
      ]

    思路:先建立dict的邻接链表,例子中的结果如下:

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

    在Word LadderI的基础上,由于要重新构建结果集,因此要自己创建一个Node类,保存每一个节点的上一个节点,这样在找到最短结果的时候,以此找到该节点的上一个节点,加入链表即可。

    需要注意的几点:

    (1)构建邻接链表前,需要把start和end加入,这样才能找到结果。

    (2)构建邻接链表的时候,对于每一个单词,一定要在每一次替换char后,再将其恢复,以便进行下一次判断。

    (3)每一层的queue用一个num来记录此层的Node个数,只要是找到一个,就证明这一层即为最短路径,设标志位为true,将该层循环之后,结束循环。

    (4)循环的过程中,需要判断节点是否已经被判断过,创建一个Set用于记录所有判断过的节点。

    代码:

    public class Solution {
        private class Node{
            public Node pre;
            public String val;
            public Node(Node p, String s){
                pre = p;
                val = s;
            }
        }
        public List<List<String>> findLadders(String start, String end, Set<String> dict) {
            dict.add(start);
            dict.add(end); //注意(1)
            Map<String, Set<String>> neighbours = calNeighbours(dict);
            
            List<List<String>> req = new ArrayList<List<String>>();
            
            LinkedList<Node> queue = new LinkedList<Node>();
            queue.offer(new Node(null, start)); //开始节点的前一个为null
            
            Set<String> visited = new HashSet<String>(); //注意(4)
            boolean flag = false; //注意(3)
            while(!queue.isEmpty() || visited.size() == dict.size()){
                int num = queue.size();
                for(int i = 0 ; i < num ; i++){
                    Node n = queue.poll();
                    if(end.equals(n.val)){
                        findPath(n, req);
                        flag = true; //注意(3)
                    }else{
                        Set<String> temp = neighbours.get(n.val);
                        if(temp == null || temp.size() == 0)
                            continue;
                        else{
                            for(String s : temp){
                                if(!visited.contains(s)){ //注意(4)
                                    queue.offer(new Node(n, s));
                                }
                            }
                        }
                    }
                    visited.add(n.val);//注意(4)
                }
                if(flag)
                    break;
            }
            if(!flag) // 如果flag为false,证明无解
                return new ArrayList<List<String>>();
            return req;
        }
        
        private void findPath(Node n, List<List<String>> req) {
            // TODO Auto-generated method stub
            List<String> temp = new ArrayList<String>();
            while(n != null){
                temp.add(0, n.val);
                n = n.pre;
            }
            req.add(temp);
        }
        public Map<String, Set<String>> calNeighbours(Set<String> dict) {
            Map<String, Set<String>> neighbours = new HashMap<String, Set<String>>();
            
            for(String str : dict){
                int len = str.length();
                char[] chars = str.toCharArray();
                
                for(int i = 0 ; i < len ; i++){
                    char old = chars[i]; //注意(2)
                    for(char c = 'a' ; c <= 'z' ; c++){
                        if(c == chars[i])
                            continue;
                        chars[i] = c;
                        String newstr = new String(chars);
                        
                        if(dict.contains(newstr)) {
                            Set<String> set = neighbours.get(str);
                            if(set != null)
                                set.add(newstr);
                            else{
                                Set<String> newset = new HashSet<String>();
                                newset.add(newstr);
                                neighbours.put(str, newset);
                            }
                        }
                        chars[i] = old ; //注意(2)引用型变量 每一次用完要还原 
                    } // end fot c
                } // end for len
            } // end for str
    
            return neighbours;
        }
    }

    AC时间为 1120ms左右,因此还有很大的改进空间,继续新的思路。

    改进1:

    在判断去重的时候,不仅要去掉已经走过的String,还要去掉同层的其他String,同层的路径一定回比下一层的要短,因此要在上一次循环的时候去掉所有新添加的,因此,每一层新建立一个remove的集合,存储该层需要去掉的节点。

    修改后代码(只添加了三行 24, 39, 45):

    public class Solution {
        private class Node{
            public Node pre;
            public String val;
            public Node(Node p, String s){
                pre = p;
                val = s;
            }
        }
        public List<List<String>> findLadders(String start, String end, Set<String> dict) {
            dict.add(start);
            dict.add(end); //注意(1)
            Map<String, Set<String>> neighbours = calNeighbours(dict);
            
            List<List<String>> req = new ArrayList<List<String>>();
            
            LinkedList<Node> queue = new LinkedList<Node>();
            queue.offer(new Node(null, start)); //开始节点的前一个为null
            
            Set<String> visited = new HashSet<String>(); //注意(4)
            boolean flag = false; //注意(3)
            while(!queue.isEmpty() || visited.size() == dict.size()){
                int num = queue.size();
                Set<String> remove = new HashSet<String>(); // 新加判断 每一层需要删除的集合
                for(int i = 0 ; i < num ; i++){
                    Node n = queue.poll();
                    if(end.equals(n.val)){
                        findPath(n, req);
                        flag = true; //注意(3)
                    }else{
                        Set<String> temp = neighbours.get(n.val);
                        if(temp == null || temp.size() == 0)
                            continue;
                        else{
                            for(String s : temp){
                                if(!visited.contains(s)){ //注意(4)
                                    queue.offer(new Node(n, s));
                                }
                                remove.add(s);
                            }
                        }
                    }
                    //visited.add(n.val);  // 可以去掉此处
                }
                visited.addAll(remove);
                if(flag)
                    break;
            }
            if(!flag) // 如果flag为false,证明无解
                return new ArrayList<List<String>>();
            return req;
        }
        
        private void findPath(Node n, List<List<String>> req) {
            // TODO Auto-generated method stub
            List<String> temp = new ArrayList<String>();
            while(n != null){
                temp.add(0, n.val); 
                n = n.pre;
            }
            req.add(temp);
        }
        public Map<String, Set<String>> calNeighbours(Set<String> dict) {
            Map<String, Set<String>> neighbours = new HashMap<String, Set<String>>();
            
            for(String str : dict){
                int len = str.length();
                char[] chars = str.toCharArray();
                
                for(int i = 0 ; i < len ; i++){
                    char old = chars[i]; //注意(2)
                    for(char c = 'a' ; c <= 'z' ; c++){
                        if(c == chars[i])
                            continue;
                        chars[i] = c;
                        String newstr = new String(chars);
                        
                        if(dict.contains(newstr)) {
                            Set<String> set = neighbours.get(str);
                            if(set != null)
                                set.add(newstr);
                            else{
                                Set<String> newset = new HashSet<String>();
                                newset.add(newstr);
                                neighbours.put(str, newset);
                            }
                        }
                        chars[i] = old ; //注意(2)引用型变量 每一次用完要还原 
                    } // end fot c
                } // end for len
            } // end for str
    
            return neighbours;
        }
    }

     改完之后 AC的时间大概是 820ms 应该还有继续修改的空间,持续更新.....

    参考链接:

    http://www.cnblogs.com/springfor/p/3893529.html

    http://www.cnblogs.com/shawnhue/archive/2013/06/05/leetcode_126.html

  • 相关阅读:
    【原】Spark on YARN
    【原】Spark Standalone模式
    【原】日志处理-Spark
    怎样从官网下载Spring的jar包
    成功安装mysql(mysql-5.5.32-winx64.msi)后,为何服务管理器里找不到MYSQL服务名?
    SQL如何取得一个面的中心点
    Kindle2018 一周使用报告
    迅雷导致文件损坏
    苹果中国官网全面更新,官翻产品不容错过!
    如何选择windows 10 系统中默认打开程序
  • 原文地址:https://www.cnblogs.com/TinyBobo/p/4575009.html
Copyright © 2011-2022 走看看