兩個單詞間的最短路徑(單源最短路徑/相鄰單詞)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 transformed word must exist in the word list. Note that beginWord is not a transformed word.

For example,spa

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

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.orm

Note:ci

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.

UPDATE (2017/1/20):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.rem

解決:字符串

【題意】和當前單詞相鄰的單詞是:對當前單詞改變一個字母且在字典中存在的單詞。get

① 這個就是圖論算法中的單源最短路, 求單源最短路比較通用的算法是BFS和Dijkstra, 其區別是BFS不能用於帶權重的圖中, 然後者能夠, 能夠看出在本題中兩個字符串之間是無權重的, 也就是若是連通就是1, 不聯通就是無窮. BFS和Dijkstra的區別是前者的時間複雜度是O(n), 後者最多優化到O(m log n), 因此若是條件成立通常選擇BFS要更好.string

以題目中的例子爲例:

  level = 1    hit   dict = [hot, dot, dog, lot, log,cog]
         ait bit cit ... xit yit zit ,  hat hbt hct ... hot ... hxt hyt hzt ,  hia hib hic ... hix hiy hiz
  level = 2    hot  dict = [dot, dog, lot, log,cog]
         aot bot cot dot ...  lot ... xot yot zot,hat hbt hct ... hxt hyt hzt,hoa hob hoc ... hox hoy hoz
  level = 3    dot lot  dict = [dog,log,cog]
         aot bot ... yot zot,dat dbt ...dyt dzt,doa dob ... dog .. doy doz,
         aot bot ... yot zot,lat lbt ... lyt lzt,loa lob ... log... loy loz
  level = 4   dog log dict = [cog] 
         aog bog cog
  level = 5   cog  dict = []

class Solution {//99ms
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        if(beginWord == null || endWord == null || beginWord.length() == 0 || endWord.length() == 0){
            return 0;
        }
        Set<String> set = new HashSet<>(wordList);//去重,而且去除了beginWord相同的單詞。
        if(set.contains(beginWord)){
            set.remove(beginWord);
        }

        Queue<String> queue = new LinkedList<>();
        int level = 1;
        int curnum = 1; //當前層待處理的節點數
        int nextnum = 0;//記錄下一層節點數
        queue.offer(beginWord);
        while(! queue.isEmpty()){
            String word = queue.poll();
            curnum --;
            for (int i = 0;i < word.length() ;i ++ ) {//更換單詞
                char[] wchar = word.toCharArray();
                for (char j = 'a';j <= 'z' ;j ++ ) {
                    wchar[i] = j;
                    String tmp = new String(wchar);
                    if(set.contains(tmp)){
                        if(tmp.equals(endWord)){
                            return level + 1;
                        }
                        nextnum ++;
                        queue.add(tmp);
                        set.remove(tmp);//要將遍歷到的單詞從字典中刪除
                    }
                }
            }
            if(curnum == 0){
                curnum = nextnum;
                nextnum = 0;
                level ++;
            }
        }
        return 0;
    }
}

② 對上面的方法進行優化,若是咱們從兩頭掃,掃到中間任何一個word可以串聯起來均可以,若是沒有找到能夠串聯的word,那麼返回0。

class Solution {//23ms
    public int ladderLength(String beginWord, String endWord, List<String> wordList){
        if (wordList == null || wordList.size() == 0){
            return 0;
        }
        Set<String> set = new HashSet<>(wordList);
        if (! set.contains(endWord)) return 0;//【注意】endWord是在字典裏的,兩端查找須要額外判斷
        if (beginWord.equals(endWord)) return 1;
        Set<String> beginSet = new HashSet<>();
        Set<String> endSet = new HashSet<>();
        beginSet.add(beginWord);
        set.remove(beginWord);
        endSet.add(endWord);
        set.remove(endWord);
        return twoEndBFS(beginSet,endSet,set,2);
    }
    public int twoEndBFS(Set<String> beginSet,Set<String> endSet,Set<String> set,int level){
        if (beginSet.isEmpty() || endSet.isEmpty()) return 0;
        if (beginSet.size() > endSet.size()) return twoEndBFS(endSet,beginSet,set,level);
        Set<String> tmp = new HashSet<>();//做爲從當前層開始的beginSet
        for (String word : beginSet){
            char[] wchar = word.toCharArray();
            for (int i = 0;i < wchar.length;i ++){
                char c = wchar[i];
                for (char j = 'a';j <= 'z';j ++){
                    wchar[i] = j;
                    String newWord = new String(wchar);
                    if (endSet.contains(newWord)) return level;//能夠接上
                    if (set.contains(newWord)){
                        set.remove(newWord);
                        tmp.add(newWord);
                    }
                }
                wchar[i] = c;
            }
        }
        return twoEndBFS(tmp,endSet,set,level + 1);     } }

相關文章
相關標籤/搜索