【LeetCode】WordLadder||

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.

这道题目跟word ladder的区别在于要记录下来所遍历过的最短路径,我首先想到的用DFS算法来解决,DFS过程中记录下来路径,但是由于需要遍历到所有的路径所以时间

消耗比较大,我又设置了一个全局的遍历来记录最小的长度,当遍历取得最小长度后,在此后的遍历中如果大于最小长度则直接返回。但是由于存在一些之前多遍历的路径最后还是时间超时。

public class Solution {
    public ArrayList<ArrayList<String>> findLadders(String start, String end, HashSet<String> dict) {
        ArrayList<ArrayList<String>> ree = new ArrayList<ArrayList<String>>();
        if(dict.isEmpty())
            return re;
        if(start.equals(end))
            return re;
        
        ArrayList<String> init = new ArrayList<String>();
        init.add(start);
        int depth=0;
        DFS(start,end,dict,init,depth);
        Iterator<ArrayList<String>> it = re.iterator();
        while(it.hasNext()){
            ArrayList<String> temps = it.next();
            if(temps.size()==mindepth+1)
                ree.add(temps);
        }
        return re;
        
    }
    public int mindepth=-1;
    public  ArrayList<ArrayList<String>> re = new ArrayList<ArrayList<String>>();
    private void DFS(String start, String end, HashSet<String> dict,ArrayList<String> init,int depth) {
        depth++;
        if(mindepth!=-1&&depth>mindepth)
            return;
        if(dict.isEmpty())
            return;
        int len = start.length();
        char[] sr = start.toCharArray();
        for(int i=0;i<len;i++){
            char temp = sr[i];
            for(char c='a';c<='z';c++){
                if(temp==c)
                    continue;
                sr[i]=c;
                String ns = String.valueOf(sr);
                if(ns.equals(end)){
                    if(mindepth==-1){
                        mindepth=depth;
                    }else{
                        if(depth<mindepth){
                            mindepth=depth;
                        }
                    }
                        
                    init.add(end);
                    ArrayList<String> al = new ArrayList<String>();
                    int m=0;
                    while(m<init.size()){
                        al.add(m, init.get(m));
                        m++;
                    }
                    re.add(al);
                    init.remove(init.size()-1);
                    
                }
                if(dict.contains(ns)){
                    init.add(ns);
                    dict.remove(ns);
                    DFS(ns,end,dict,init,depth);
                    
                    dict.add(ns);
                    init.remove(init.size()-1);
                }

            }
            sr[i]=temp;
        }
        return;
    }
    
}

 

 

后面还是想到用BFS算法,但是此问题的难点在于对路径的记录上面。

整个过程可以分成两个部分:先通过BFS从start找到end,在找的过程中需要记录前驱单词,再用DFS反向找回完整路径。

但是用Java实现上述过程会遇到TLE。为了能让用时尽可能短,有如下几点需要注意的地方:

1. 由于最后生成路径的时候,需要从end找到start构造ArrayList,即使用LinkList来协助构造,性能也不好。解决办法:不从start找end了,反过来从end找start,找到后,再从start往end构造路径,性能会有明显提升。

2. 在BFS过程中,需要替换String的每一位字符,先转换成char数组再操作,性能也会有明显提升。

3. 在BFS过程中,注意避免一些不必要的搜索

 

分析:本题主要的框架和上一题是一样,但是还要解决两个额外的问题:一、 怎样保证求得所有的最短路径;二、 怎样构造这些路径

第一问题:

  • 不能像上一题那样,找到一个单词相邻的单词后就立马把它从字典里删除,因为当前层还有其他单词可能和该单词是相邻的,这也是一条最短路径,比如hot->hog->dog->dig和hot->dot->dog->dig,找到hog的相邻dog后不能立马删除,因为和hog同一层的单词dot的相邻也是dog,两者均是一条最短路径。但是为了避免进入死循环,再hog、dot这一层的单词便利完成后dog还是得从字典中删除。即等到当前层所有单词遍历完后,和他们相邻且在字典中的单词要从字典中删除。
  • 为了解决上面的问题,每次层序遍历结束后将tempqueue赋值给queue,然后将temequeue清空,重新记录下层需要遍历的数据
  • 当某一层的某个单词转换可以得到end单词时,表示已经找到一条最短路径,那么该单词的其他转换就可以跳过。并且遍历完这一层以后就可以跳出循环,因为再往下遍历,肯定会超过最短路径长度
public class NSolution {
    
    public ArrayList<ArrayList<String>> findLadders(String start, String end, HashSet<String> dict) {
        Map<String,ArrayList<String>> map = new HashMap<String,ArrayList<String>>();
        ArrayList<ArrayList<String>> relist = new ArrayList<ArrayList<String>>();
        if(dict.isEmpty())
            return relist;
        if(start.equals(end))
            return relist;
        Iterator<String> it = dict.iterator();
        HashSet<String> tempdict = new HashSet<String>();
        
        while(it.hasNext()){
            String str = it.next();
            
            tempdict.add(str);
            map.put(str, new ArrayList<String>());    
        }       
        Queue<String> queue = new LinkedList<String>();
        Queue<String> tempqueue = new LinkedList<String>();  
        
        queue.add(start);       
        map.put(start,new ArrayList<String>());
        boolean flag = true;
        
        while(dict!=null&&!queue.isEmpty()){
            String str = queue.peek();
            char[] sr = str.toCharArray();
            queue.poll();
            int len = str.length();
            for(int i=0;i<len;i++){
                char temp = sr[i];
                for(char c ='a';c<='z';c++){
                    if(c==temp)
                        continue;
                    sr[i]=c;
                    String ns = String.valueOf(sr);
                    if(ns.equals(end)){
                        flag=false;
                        
                        ArrayList<String> artemp = new ArrayList<String>();
                        artemp= map.get(ns);
                        if(ns.isEmpty()){
                            artemp.add(str);
                        }else{
                            Iterator<String> ita = artemp.iterator();
                            boolean bol = false;
                            while(ita.hasNext()){
                                if(ita.next().equals(str)){
                                    bol = true;;
                                }
                            }
                            if(!bol){
                                artemp.add(str);
                            }
                        }
                            
                        
                        
                    }
                        
                    if(dict.contains(ns)){
                        tempdict.remove(ns);
                        if(!tempqueue.contains(ns)){
                            tempqueue.offer(ns);
                        }
                        ArrayList<String> artemp = new ArrayList<String>();
                        artemp= map.get(ns);
                        if(ns.isEmpty()){
                            artemp.add(str);
                        }else{
                            Iterator<String> ita = artemp.iterator();
                            boolean bol = false;
                            while(ita.hasNext()){
                                if(ita.next().equals(str)){
                                    bol = true;;
                                }
                            }
                            if(!bol){
                                artemp.add(str);
                            }
                        }
                        
                        
                        
                    }
                }
                sr[i]=temp;
            }
                
                if(queue.isEmpty()&&flag){
                    queue=tempqueue;
                    tempqueue= new LinkedList<String>();
                    dict =new HashSet<String>();
                    Iterator<String> iitt = tempdict.iterator();
                    while(iitt.hasNext()){
                        dict.add(iitt.next());
                    }
                    
                    
                    
                }
    
        }
        ArrayList<String> tmparray = new ArrayList<String>();
        tmparray.add(end);
        buildpath(start, end, map, tmparray, relist);
        
        return relist;
        
    }

      public void buildpath(String start, String end,
              Map<String, ArrayList<String>> map, ArrayList<String> tmparray,
              ArrayList<ArrayList<String>> res) {
          ArrayList<String> pre = map.get(end);
           if (end.equals(start)) {
               ArrayList<String> tmparray2 = new ArrayList<String>(tmparray);
               Collections.reverse(tmparray2);
               res.add(tmparray2);
               return;
           }
           for (String s: pre) {
               tmparray.add(s);
               buildpath(start, s, map, tmparray, res);
               tmparray.remove(tmparray.size() - 1);
           }
              
      }
}

 

posted @ 2014-05-15 22:22  一弦一仙  阅读(245)  评论(0编辑  收藏  举报