1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
private final int[][] DIRECTIONS = new int[][] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };

public boolean containsCycle(char[][] grid) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] >= 97 && hasCycle(grid, i, j, -1, -1)) {
return true;
}
}
}
return false;
}

private boolean hasCycle(char[][] grid, int row, int col, int prevRow, int prevCol) {
char currChar = grid[row][col];
grid[row][col] -= 32;
for (int[] direction : DIRECTIONS) {
int newRow = row + direction[0];
int newCol = col + direction[1];
if (!isOutBound(grid, newRow, newCol) && (newRow != prevRow || newCol != prevCol) &&
Character.toLowerCase(grid[newRow][newCol]) == currChar) {
if (grid[newRow][newCol] != currChar) {
return true;
} else if (hasCycle(grid, newRow, newCol, row, col)) {
return true;
}
}
}
return false;
}

private boolean isOutBound(char[][] grid, int row, int col) {
return row < 0 || row >= grid.length || col < 0 || col >= grid[0].length;
}
}

真杂种操了. 第21行第二个扩起来的两个条件, 判断不能是走回头路那个, 那是or不能写成and. 写成and是既不能有相同的row也不能有相同的col. 这肯定不对, 二者一个不一样即可.

我们visit过的地方, 如果走不通, 那这个地方一定不在cycle中. 可以用反证法来证明. 假设它在cycle中, 那么一定会有路走, 要么是走之前没走过的要么就是走到了之前走过的地方, 形成cycle. 因此只要是back回来的, 标记过的走过的点都不恢复. 之后遍历的时候, 如果走过之前走过的点, 这说明遇到了cycle. 问题是a标记好的走过的点如果我们在找b的cycle的时候不混淆呢? 也就是b走过的点也要标记, 如何区分a做过的点和b走过的点呢? 我想的是转大写. a走过的点统一变成‘A’, b走过的点统一变成‘B’. 这样就不会混淆了, 否则我们会误认为a标记的点是b标记的而错误地以为形成了cycle.

记得大写从65开始, 小写从97开始.

时间复杂度: O(m * n)
空间复杂度: O(m * n)