Home
avatar

Kaixun

Top 150 · 图的 BFS(3 题)

最短步数 BFS:棋盘、基因链与单词接龙。

本模块共 3 题,属于 LeetCode 面试经典 150 题 系列。

909. 蛇梯棋

难度: 中等

力扣做题

思路

bfs模板,每次入队所有可达点,visited数组避免环形访问

代码

class Solution {
    public int snakesAndLadders(int[][] board) {
        Queue<Integer> queue = new ArrayDeque<>();
        int n = board.length;
        boolean[] visited = new boolean[n * n + 1];

        queue.offer(1);
        visited[1] = true;
        int step = 0;

        while(!queue.isEmpty()){
            int size = queue.size();
            while(size-- > 0){
                int i = queue.poll();
                if (i == n * n)return step;

                for(int next = i+1;next<=Math.min(i + 6, n*n);next++){
                    int row = n - 1 - (next-1)/n;
                    int bottomRow = n-1-row;
                    int col = (bottomRow%2!=0) ? n-1 - (next-1)%n: (next-1)%n;
                    int realNext = next;
                    if(board[row][col] != -1)realNext = board[row][col];
                    if(visited[realNext] == true)continue;
                    queue.offer(realNext);
                    visited[realNext] = true;
                }
            }
            step++;
        }
        return -1;
    }
}

复杂度

  • 时间:O(n2)O(n^2)
  • 空间:O(n2)O(n^2)

备注

题目叽里咕噜说一大堆。。。。


433. 最小基因变化

难度: 中等

力扣做题

思路

同样bfs,用set当visited

代码

class Solution {
    Set<String> set;
    public int minMutation(String startGene, String endGene, String[] bank) {
        set = new HashSet<>();
        for (int i = 0; i < bank.length; i++) {
            set.add(bank[i]);
        }
        
        Queue<String> queue = new ArrayDeque<>();
        queue.offer(startGene);
        int step = 0;
        set.add(startGene);

        while(!queue.isEmpty()){
            int size = queue.size();
            while(size-- > 0){
                String cur = queue.poll();
                if(cur.equals(endGene))return step;
                for (String next : bank) {
                    if (set.contains(next) && oneDiff(cur, next)) {
                        queue.offer(next);
                        set.remove(next);
                    }
                }
            }
            step++;
        }
        return -1;
    }
    public boolean oneDiff(String a,String b){
        int diff =0;
        for (int j = 0; j < 8; j++) {
            if(a.charAt(j) != b.charAt(j))diff++;
        }
        return diff==1;
    }
}

复杂度

  • 时间:O(n2)O(n^2)
  • 空间:O(n)O(n)

备注

时间O(n)O(n)的做法是不遍历bank,遍历24种替换组合

class Solution {
    Set<String> set;
    public int minMutation(String startGene, String endGene, String[] bank) {
        set = new HashSet<>();
        char[] genes = {'A', 'C', 'G', 'T'};

        for (int i = 0; i < bank.length; i++) {
            set.add(bank[i]);
        }
        
        Queue<String> queue = new ArrayDeque<>();
        queue.offer(startGene);
        int step = 0;
        set.add(startGene);

        while(!queue.isEmpty()){
            int size = queue.size();
            while(size-- > 0){
                String cur = queue.poll();
                if(cur.equals(endGene))return step;
                for (int i = 0; i < 8; i++) {
                    char[] arr = cur.toCharArray();
                    for (char c : genes) {
                        if (c == arr[i]) continue;
                        arr[i] = c;
                        String next = new String(arr);
                        if (set.contains(next) && oneDiff(cur, next)) {
                            queue.offer(next);
                            set.remove(next);
                        }
                    }
                }
            }
            step++;
        }
        return -1;
    }
    public boolean oneDiff(String a,String b){
        int diff =0;
        for (int j = 0; j < 8; j++) {
            if(a.charAt(j) != b.charAt(j))diff++;
        }
        return diff==1;
    }
}

127. 单词接龙

难度: 困难

力扣做题

思路

同样做bfs,每次改一个字母

代码

class Solution {
    Set<String> set;
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        set = new HashSet<>();
        char[] genes = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

        for (int i = 0; i < wordList.size(); i++) {
            set.add(wordList.get(i));
        }
        
        Queue<String> queue = new ArrayDeque<>();
        queue.offer(beginWord);
        int step = 0;
        set.add(beginWord);

        while(!queue.isEmpty()){
            int size = queue.size();
            while(size-- > 0){
                String cur = queue.poll();
                if(cur.equals(endWord))return step+1;
                for (int i = 0; i < cur.length(); i++) {
                    char[] arr = cur.toCharArray();
                    for (char c : genes) {
                        if (c == arr[i]) continue;
                        arr[i] = c;
                        String next = new String(arr);
                        if (set.contains(next)) {
                            queue.offer(next);
                            set.remove(next);
                        }
                    }
                }
            }
            step++;
        }
        return 0;
    }

}

复杂度

  • 时间:O(nL2)O(n \cdot L^2)
  • 空间:O(nL)O(n*L)

备注

可以用双向bfs,把期望时间复杂度变成O(nL)O(n*L)

class Solution {
    char[] genes = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Set<String> dict = new HashSet<>(wordList);
        if (!dict.contains(endWord)) return 0;

        Set<String> beginSet = new HashSet<>();
        Set<String> endSet = new HashSet<>();
        beginSet.add(beginWord);
        endSet.add(endWord);
        int step = 1;  // 起点、终点各算 1

        while (!beginSet.isEmpty() && !endSet.isEmpty()) {
            // 总是扩较小的一边,剪枝
            if (beginSet.size() > endSet.size()) {
                Set<String> tmp = beginSet;
                beginSet = endSet;
                endSet = tmp;
            }

            Set<String> nextSet = new HashSet<>();
            for (String cur : beginSet) {
                char[] arr = cur.toCharArray();
                for (int i = 0; i < arr.length; i++) {
                    char old = arr[i];
                    for (char c : genes) {
                        if (c == old) continue;
                        arr[i] = c;
                        String next = new String(arr);
                        if (endSet.contains(next)) return step + 1; // 两端相遇
                        if (dict.contains(next)) {
                            nextSet.add(next);
                            dict.remove(next);
                        }
                    }
                    arr[i] = old;
                }
            }
            beginSet = nextSet;
            step++;
        }
        return 0;
    }
}

Top150 BFS