leetcode算法基础 第八天 深搜/广搜

1091. 二进制矩阵中的最短路径

题目
使用广搜,每次将八个方向的值为0点加入队列,加入队列时将值改为1,以此类推,直到找到最终位置。

public int shortestPathBinaryMatrix(int[][] grid) {
    if (grid[0][0] == 1 || grid[grid.length-1][grid[0].length-1] == 1) return -1;
    Queue<int[]> queue = new LinkedList<>();
    int[][] vectors = {{0,1},{0,-1},{1,0},{-1,0},{-1,-1},{-1,1},{1,-1},{1,1}};
    queue.add(new int[]{0,0});
    grid[0][0] = 1;
    int len = 1;
    while (!queue.isEmpty()){
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            int[] n = queue.poll();
            if (n[0] == grid.length - 1 && n[1] == grid[0].length - 1) return len;
            for (int[] v : vectors) {
                int nr = n[0] + v[0];
                int nl = n[1] + v[1];
                if (nr >= 0 && nr < grid.length && nl >= 0 && nl < grid[0].length && grid[nr][nl] == 0) {
                    grid[nr][nl] = 1; //加入队列时就将值改为1
                    queue.add(new int[]{nr, nl});
                }
            }
        }
        len++;
    }
    return -1;
}

130. 被围绕的区域

题目
深搜和广搜都可以从边界出发,先把边界上和 O 连通点找到, 把这些变成 A,然后遍历整个 board 把 O 变成 X, 把 A 变成 O

public void solve(char[][] board) {
    int r = board.length;
    if (r == 0) return;
    int l = board[0].length;
    for (int i = 0; i < r; i++) {
        dfs(i, 0, board);
        dfs(i, l - 1, board);
    }
    for (int i = 1; i < l - 1; i++) {
        dfs(0, i, board);
        dfs(r - 1, i, board);
    }
    for (int i = 0; i < r; i++) {
        for (int j = 0; j < l; j++) {
            if (board[i][j] == 'A') {
                board[i][j] = 'O';
            } else if (board[i][j] == 'O') {
                board[i][j] = 'X';
            }
        }
    }
}

public void dfs(int i, int j, char[][] board){
    if(i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] == 'X' || board[i][j] == 'A') return;
    board[i][j] = 'A';
    dfs(i - 1, j, board);
    dfs(i + 1, j, board);
    dfs(i, j - 1, board);
    dfs(i, j + 1, board);
}

并查集,我们可以将所有的O连通起来,并将所有边界的O与一个虚拟节点连起来,最后遍历一遍遇到O判断它跟虚拟节点是不是在一个集合里面。

int[][] dirs = new int[][] {{1,0},{-1,0},{0,1},{0,-1}};
int[] father;

public void solve1(char[][] board) {
    int m = board.length;
    int n = board[0].length;
    int dummy = m * n; // 虚拟节点
    init(m * n);
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (board[i][j] == 'O') {
                // 边界节点
                if (i == 0 || j == 0 || i == m - 1 || j == n - 1) {
                    union(index(i, j, n), dummy);
                } else {
                    // 非边界节点
                    for (int[] dir : dirs) {
                        int x = i + dir[0];
                        int y = j + dir[1];
                        if (board[x][y] == 'O') {
                            union(index(i, j, n), index(x, y, n));
                        }
                    }
                }
            }
        }
    }
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (board[i][j] == 'O') {
                // 跟虚拟节点不连通,改成X
                if (!connected(index(i, j, n), dummy)) {
                    board[i][j] = 'X';
                }
            }
        }
    }

}

int index(int i, int j, int n) {
    return i * n + j;
}

void init(int n) {
    this.father = new int[n + 1];
    for (int i = 0; i <= n; i++) {
        father[i] = i;
    }
}

int find(int x) {
    if (father[x] != x) father[x] = find(father[x]);
    return father[x];
}

void union(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if (fx != fy) {
        father[fx] = fy;
    }
}

boolean connected(int x, int y) {
    return find(x) == find(y);
}

797. 所有可能的路径

题目
这道题就是标准的回溯,当检测到终点时,加入该路径。

List<List<Integer>> re = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
    path.add(0);
    backtracking(0, graph, 0);
    return re;
}

public void backtracking(int startIndex, int[][] graph, int l){
    if (path.getLast() == graph.length - 1){
        re.add(new ArrayList<>(path));
        return;
    }
    for (int i = startIndex; i < graph[l].length; i++){
        path.add(graph[l][i]);
        backtracking(0, graph, graph[l][i]);
        path.removeLast();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值