Given a knight in a chessboard (a binary matrix with 0 as empty and 1 as barrier) with a source position, find the shortest path to a destination position, return the length of the route. Return -1 if knight can not reached.
Notice
source and destination must be empty. Knight can not enter the barrier.
Have you met this question in a real interview? Yes Clarification If the knight is at (x, y), he can get to the following positions in one step:
(x + 1, y + 2)
(x + 1, y - 2)
(x - 1, y + 2)
(x - 1, y - 2)
(x + 2, y + 1)
(x + 2, y - 1)
(x - 2, y + 1)
(x - 2, y - 1)
public int shortestPath(boolean[][] grid, Point source, Point destination) {
if (grid == null || grid.length == 0) return -1;
int R = grid.length;
int C = grid[0].length;
int[] dx = new int[]{1, 1, -1, -1, 2, 2, -2, -2};
int[] dy = new int[]{2, -2, 2, -2, 1, -1, 1, -1};
if (grid[source.x][source.y] || grid[destination.x][destination.y]) {
return -1;
}
int ret = 0;
Deque<Point> queue = new LinkedList<>();
queue.addFirst(source);
// bfs过的点标记为1,即不会重复
while (! queue.isEmpty()) {
int size = queue.size();
ret++;
for (int j = 0; j < size; ++j) {
Point point = queue.removeLast();
for (int i = 0; i < 8; ++i) {
int m = point.x + dx[i];
int n = point.y + dy[i];
if (m < 0 || m >= grid.length || n < 0 || n >= grid[0].length) {
continue;
}
if (m == destination.x && n == destination.y) return ret;
if (! grid[m][n]) {
grid[m][n] = true;
queue.addFirst(new Point(m, n));
}
}
}
}
return -1;
}
// 双向BFS,sqrt(V + E)时间
public int shortestPath(boolean[][] grid, Point source, Point destination) {
if (grid == null || grid.length == 0) return -1;
int R = grid.length;
int C = grid[0].length;
int[] dx = new int[]{1, 1, -1, -1, 2, 2, -2, -2};
int[] dy = new int[]{2, -2, 2, -2, 1, -1, 1, -1};
if (grid[source.x][source.y] || grid[destination.x][destination.y]) {
return -1;
}
// 把grid改为int[][],把两边bfs visited的点分别标记为 2 和 3。
int[][] graph = new int[R][C];
for (int i = 0; i < R; ++i) {
for (int j = 0; j < C; ++j) {
graph[i][j] = grid[i][j] ? 1 : 0;
}
}
// 开始双向bfs
Deque<Point> q1 = new LinkedList<>();
Deque<Point> q2 = new LinkedList<>();
q1.addFirst(source);
q2.addFirst(destination);
graph[source.x][source.y] = 2;
graph[destination.x][destination.y] = 3;
int step = 0;
// 若一方队列为空,则fail
while (! q1.isEmpty() && ! q2.isEmpty()) {
int smallStep = 0; // !!!这里很关键!!!!
// bfs1, 进行一层
int size1 = q1.size();
smallStep++;
for (int i = 0; i < size1; ++i) {
Point p = q1.removeLast();
for (int j = 0; j < 8; ++j) {
int m = p.x + dx[j];
int n = p.y + dy[j];
if (m < 0 || m >= R || n < 0 || n >= C) continue;
if (graph[m][n] == 3) {
// 此时相遇
return step * 2 + smallStep;
}
if (graph[m][n] == 0) {
graph[m][n] = 2;
q1.addFirst(new Point(m, n));
}
}
}
// bfs2,进行一层
int size2 = q2.size();
smallStep++;
for (int i = 0; i < size2; ++i) {
Point p = q2.removeLast();
for (int j = 0; j < 8; ++j) {
int m = p.x + dx[j];
int n = p.y + dy[j];
if (m < 0 || m >= R || n < 0 || n >= C) continue;
if (graph[m][n] == 2) {
// 此时相遇
return step * 2 + smallStep;
}
if (graph[m][n] == 0) {
graph[m][n] = 3;
q2.addFirst(new Point(m, n));
}
}
}
step++;
}
return -1;
}
class Solution {
bool isValid(const vector<vector<bool>>& grid, Point& point) {
int r = point.x, c = point.y;
if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size() || grid[r][c])
return false;
else
return true;
}
public:
/**
* @param grid: a chessboard included 0 (false) and 1 (true)
* @param source: a point
* @param destination: a point
* @return: the shortest path
*/
int shortestPath(vector<vector<bool>> &grid, Point &source, Point &destination) {
int dr[8]{1, 1, -1, -1, 2, 2, -2, -2};
int dc[8]{2, -2, 2, -2, 1, -1, 1, -1};
int R = grid.size(), C = grid[0].size();
deque<Point> q;
int stepCount = 0;
q.push_back(source);
grid[source.x][source.y] = 1;
while (! q.empty()) {
int size = q.size();
for (int i = 0; i < size; ++i) {
Point curr = q.front(); q.pop_front();
for (int k = 0; k < 8; ++k) {
Point next{curr.x + dr[k], curr.y + dc[k]};
if (isValid(grid, next)) {
if (next.x == destination.x && next.y == destination.y) {
return stepCount + 1;
}
q.push_back(next);
grid[next.x][next.y] = 1;
}
}
}
++stepCount;
}
return -1;
}
};