【LeetCode】BFS 總結


BFS(廣度優先搜索) 常用來解決最短路徑問題。

第一次便利到目的節點時,所經過的路徑是最短路徑。

幾個要點:

  • 只能用來求解無權圖的最短路徑問題
  • 隊列:用來存儲每一層便利得到的節點
  • 標記:對於遍歷過的結點,應將其標記,以防重復訪問

279. 完全平方數

題目描述

給定正整數 n,找到若干個完全平方數(比如 1, 4, 9, 16, ...)使得它們的和等於 n。你需要讓組成和的完全平方數的個數最少。

示例 1:

輸入: n = 12
輸出: 3 
解釋: 12 = 4 + 4 + 4.

示例 2:

輸入: n = 13
輸出: 2
解釋: 13 = 4 + 9.

解題思路

從 0 到 n 有 n+1 個整數,把這 n+1 個整數看做是節點。如果兩個節點之間的差是一個完全平方數,我們就說這兩個節點之間是有連接的。通過這個思路我們就可以建立一張圖。

找到 n 到 0 的最短路徑,我們就找到了 n 至少需要幾個完全平方數組成。

public int numSquares(int n) {
    List<Integer> squares = generateSquares(n);
    Queue<Integer> queue = new LinkedList<>();
    boolean[] marked = new boolean[n + 1];
    queue.add(n);
    marked[n] = true;
    int level = 0;
    while(!queue.isEmpty()){
        int size = queue.size();
        level++;
        while(size-- >0){
            int cur = queue.poll();
            for (int s : squares){
                int next = cur - s;
                if (next < 0)
                    break;
                if (next == 0)
                    return level;
                if (marked[next])
                    continue;
                queue.add(next);
                marked[next] = true;
            }
        }
    }
    return n;
}

private List<Integer> generateSquares(int n){
    List<Integer> squares = new ArrayList<>();
    int square = 1;
    int diff = 3;
    while(square <= n){
        squares.add(square);
        square += diff;
        diff += 2;
    }

    return squares;
}

127. 單詞接龍

題目描述

給定兩個單詞(beginWordendWord)和一個字典,找到從 beginWordendWord 的最短轉換序列的長度。轉換需遵循如下規則:

  1. 每次轉換只能改變一個字母。
  2. 轉換過程中的中間單詞必須是字典中的單詞。

說明:

  • 如果不存在這樣的轉換序列,返回 0。
  • 所有單詞具有相同的長度。
  • 所有單詞只由小寫字母組成。
  • 字典中不存在重復的單詞。
  • 你可以假設 beginWordendWord 是非空的,且二者不相同。

示例 1:

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

輸出: 5

解釋: 一個最短轉換序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的長度 5。

示例 2:

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

輸出: 0

解釋: endWord "cog" 不在字典中,所以無法進行轉換。

解題思路

如果兩個單詞在對應位置上只有一個字母是不同的,我們就說這兩個單詞是連接的。按照這個定義,我們可以建立一張圖。對這張圖進行 BFS 就可以找到從 beginWordendWord 的最短轉換序列的長度。

注意,字典中是不包含beginWord的,我們需要將其手動加入再建立圖。

public int ladderLength (String beginWord, String endWord, List<String> wordList) {
    wordList.add(beginWord);  // 手動加入起始單詞
    int N  = wordList.size();
    int start = N -1;
    int end = 0;
    while (end < N && !wordList.get(end).equals(endWord)) {
        end++;
    }
    if (end == N) // 目標單詞不在字典中
        return 0;
    List<Integer>[] graphic = buildGraphic(wordList);
    return getShortestPath(graphic,start,end);
}

private List<Integer>[] buildGraphic (List<String> wordList) {
    int N = wordList.size();
    List<Integer>[] graphic = new List[N];
    for (int i = 0; i < N; i++) {
        graphic[i] = new ArrayList<>();
        for (int j = 0; j < N; j++) {
            if (isConnect(wordList.get(i), wordList.get(j))) {
                graphic[i].add(j);
            }
        }
    }
    return graphic;
}

private boolean isConnect (String s1, String s2) {
    int diff = 0;
    for (int i = 0; i < s1.length() && diff <= 1; i++) {
        if (s1.charAt(i) != s2.charAt(i)) {
            diff++;
        }
    }
    return diff == 1;
}

private int getShortestPath (List<Integer>[] graphic, int start, int end) {
    Queue<Integer> queue = new LinkedList<>();
    boolean[] marked = new boolean[graphic.length];
    queue.add(start);
    marked[start] = true;
    int pathLength = 1;
    while (!queue.isEmpty()) {
        int size = queue.size();
        pathLength++;
        while (size-- > 0) {
            int cur = queue.poll();
            for (int next : graphic[cur]) {
                if (next == end) {
                    return pathLength;
                }
                if (marked[next]) {
                    continue;
                }
                queue.add(next);
                marked[next] = true;
            }
        }
    }
    return 0;
}


免責聲明!

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



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