题目是LeetCode第181场周赛的第三题,链接: 检查网格中是否存在有效路径。具体描述较长,详情请点击前面链接。
其实蛮明显的这就是一道DFS的题目,所以可以从原点(0,0)出发,递归地访问各单元格,看能否到达终点。这里需要注意的是两个单元格能连接的条件,就是一个单元格到另一单元格的延展方向(比如向右)必须在另一个单元格中有匹配的方向(比如向左)。
我自己写的一个比较繁琐的JAVA版代码可见我的Github。
上面没放代码是因为各种if-else太多,代码长度太长了,然后现在开始思考怎么使得代码更简洁。可以给方向赋值,比如上-0,右-1,下-2,左-3。然后可以发现一个规律,那就是下一个单元格的匹配方向nextDir跟当前单元格的向外延展方向currentDir之间有个关系: ( n e x t D i r + 2 ) % 4 = = c u r r e n t D i r (nextDir+2)\%4==currentDir (nextDir+2)%4==currentDir。然后对于每个方向,我们也可以提前用数组保存该方向会导致的坐标移动,比如右方向会导致(1,0)的坐标变动。而且也可以不用递归了,只要有方向可以走,就一直往下走(当然需要避免有环的存在导致死循环,所以需要记录访问过的单元格),用循环即可完成。
class Solution {
// 表示各个方向的x, y坐标变化值
private final int[][] DIRECTIONS = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
//TOP - 0, RIGHT - 1, BOTTOM - 2, LEFT - 3
private final int[][] STREETS = {{-1, -1}, {1, 3}, {0, 2}, {2, 3}, {1, 2}, {0, 3}, {0, 1}};
public boolean hasValidPath(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
if (m == 1 && n == 1) {
return true;
}
//从0,0处出发
for (int direction : STREETS[grid[0][0]]) {
if (direction == 1 || direction == 2) {
boolean[][] visited = new boolean[m][n];
int i = 0, j = 0;
int currentDir = direction;
while (true) {
//避免有环的存在造成死循环
if (visited[i][j]) {
break;
}
visited[i][j] = true;
//下一个单元格的位置
i += DIRECTIONS[currentDir][0];
j += DIRECTIONS[currentDir][1];
if (i < 0 || j < 0 || i >= m || j >= n) {
break;
}
int nextDir1 = STREETS[grid[i][j]][0], nextDir2 = STREETS[grid[i][j]][1];
//下一个单元格的某一个方向能与当前单元格向外延展方向匹配,那么下一个向外延展方向就是另一个方向
if ((nextDir1 + 2) % 4 == currentDir) {
currentDir = nextDir2;
}
else if ((nextDir2 + 2) % 4 == currentDir) {
currentDir = nextDir1;
}
else {
break;
}
if (i == m - 1 && j == n - 1) {
return true;
}
}
}
}
return false;
}
}
提交结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/4c7382aad108724608693e0efc561d71.png)
Python版代码如下:
class Solution:
def hasValidPath(self, grid: List[List[int]]) -> bool:
DIRECTIONS = [[-1, 0], [0, 1], [1, 0], [0, -1]]
STREETS = [[-1, -1], [1, 3], [0, 2], [2, 3], [1, 2], [0, 3], [0, 1]]
m = len(grid)
n = len(grid[0])
if m == 1 and n == 1:
return True
for direction in STREETS[grid[0][0]]:
if direction == 1 or direction == 2:
visited = [[False for _ in range(n)] for _ in range(m)]
currentDir = direction
i, j = 0, 0
while True:
if visited[i][j]:
break
visited[i][j] = True
i += DIRECTIONS[currentDir][0]
j += DIRECTIONS[currentDir][1]
if i < 0 or j < 0 or i >= m or j >= n:
break
nextDir1, nextDir2 = STREETS[grid[i][j]][0], STREETS[grid[i][j]][1]
if (nextDir1 + 2) % 4 == currentDir:
currentDir = nextDir2
elif (nextDir2 + 2) % 4 == currentDir:
currentDir = nextDir1
else:
break
if i == m - 1 and j == n - 1:
return True
return False
提交结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/32c2e0c2c0822eb8b0f4d87d88a866b3.png)