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();
}
}