(Java) LeetCode 127. 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.

Note:

  • 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.

Example 1:

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

Output: 5

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

Example 2:

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

Output: 0

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.

 

這是很典型的單源頭廣度優先搜索最短路徑的問題,只要想到這里,結合圖的知識就很好做了。怎么構建圖呢?首先圖的頂點顯而易見,就是每一個單詞。那么頂點之間的邊呢?就是如果頂點的單詞互相只差一個字母,頂點間就會形成邊。用第一個例子繪制的圖如下:

那么根據廣度優先搜索的步驟,構建一個隊列,之后先把源頂點加入隊列,以隊列是否為空作為條件開始循環:如果隊列不為空,逐個取出隊列中的頂點,並把它們標記為“已訪問”。對於每個取出的頂點,依次把它未訪問的頂點加入隊列,直到找到目標頂點或者所有頂點都訪問完畢。因為此題只是求最短路徑的長度,而不是路徑上都有哪些頂點,所以只需要存儲每訪問一個頂點時該頂點處在路徑的位置即可。這里我用了HashMap<String, Integer>。如果是需要存儲最短路徑本身,那么需要建立數據結構依次存儲每個頂點的前驅,並在最后追溯前驅獲得路徑上的所有頂點。

這里我用一個HashSet替換掉題目中存儲單詞的List數據結構,只是為了搜索的時候能夠快一點。至於如何獲取某個節點的鄰接節點,即和它只差一個字母的單詞,這里用了最暴力的辦法,就是把頂點單詞的每一位換成其他的25個字母,看看它在不在題目提供的字典里。詳細的標注都已經標注在代碼中,見下。

 


 

Java

class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        HashSet<String> wordSet = new HashSet<>(wordList); //替換掉題目中List結構,加速查找
        if (!wordSet.contains(endWord)) return 0; //如果目標頂點不在圖中,直接返回0
        HashMap<String, Integer> map = new HashMap<>(); //用來存儲已訪問的節點,並存儲其在路徑上的位置,相當於BFS算法中的isVisted功能
        Queue<String> q = new LinkedList<>(); //構建隊列,實現廣度優先遍歷
        q.add(beginWord); //加入源頂點
        map.put(beginWord, 1); //添加源頂點為“已訪問”,並記錄它在路徑的位置
        while (!q.isEmpty()) { //開始遍歷隊列中的頂點
            String word = q.poll(); //記錄現在正在處理的頂點
            int level = map.get(word); //記錄現在路徑的長度
            for (int i = 0; i < word.length(); i++) {
                char[] wordLetter = word.toCharArray();
                for (char j = 'a'; j <= 'z'; j++) {
                    if (wordLetter[i] == j) continue; 
                    wordLetter[i] = j; //對於每一位字母,分別替換成另外25個字母
                    String check = new String(wordLetter);
                    if (check.equals(endWord)) return map.get(word) + 1; //如果已經抵達目標節點,返回當前路徑長度+1
                    if (wordSet.contains(check) && !map.containsKey(check)) { //如果字典中存在鄰接節點,且這個鄰接節點還未被訪問
                        map.put(check, level + 1); //標記這個鄰接節點為已訪問,記錄其在路徑上的位置
                        q.add(check); //加入隊列,以供廣度搜索
                    }
                }
            }
        }
        return 0;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM