In an infinite chess board with coordinates from -infinity to +infinity, you have a knight at square [0, 0].

A knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.
1197. Minimum Knight Moves_广度优先搜索


Return the minimum number of steps needed to move the knight to the square [x, y]. It is guaranteed the answer exists.

求最短路径,标准的bfs广度优先搜索题目。本题如果没有棋盘无限大这个条件,那么完完全全是一道简单的bfs模板题型。因此考虑到棋盘范围的因素,普通的bfs肯定会超时,所以我们应该首先确定下来从起点到终点的合理范围有哪些。显而易见,如果朝着终点越来越远的方向走肯定是浪费计算时间的部分,如果简单来为棋盘来划定一下界限,起点和终点两个坐标(x1,y1), (x2,y2)围成的四边形应该是相对合理的范围。但是考虑到如果两个点在一条直线上,或者两点间的距离过近而无法完成日字跳跃的情况,我们可以将划定的棋盘范围四周分别扩大2格即可。

此外,为了方便,我们可以将起点和终点平移到正数坐标范围内。举个例子,比如:

int x = -5; // 终点x
int y = -3; // 终点y
int startX = 0; // 起点x
int starty = 0; // 起点y

先将终点移动到(0, 0),相应的起点会被移动到(5, 3)。此外,要考虑到上面提到的扩大2格的操作,因此,终点T应该是(2, 2),起点S则是(7, 5)。相应的棋盘范围则是(0, 0) 到(9, 7)之间的范围,即下图蓝色区域。

1197. Minimum Knight Moves_编程题_02

确定了棋盘范围之后,剩下的就是简单的常规bfs操作了。

 1 class Solution {
 2     public int minKnightMoves(int x, int y) {
 3         // 定义bfs可以走的八个方向
 4         int[][] directions = { { -1, -2 }, { 1, -2 }, { 2, -1 }, { 2, 1 }, { 1, 2 }, { -1, 2 }, { -2, 1 }, { -2, -1 } };
 5         int startX = 0, startY = 0; // 起始坐标
 6         if (x < 0) { // 如果终点横坐标小于0
 7             // 起点横坐标与终点横坐标同时移动x个单位
 8             startX = -x;
 9             x = 0;
10         }
11         if (y < 0) { // 如果终点纵坐标小于0
12             // 起点纵坐标与终点纵坐标同时移动y个单位
13             startY = -y;
14             y = 0;
15         }
16         // 为了将棋盘范围四周分别扩大2格,将起点和终点坐标再分别平移2个单位
17         startX += 2;
18         startY += 2;
19         x += 2;
20         y += 2;
21         // 棋盘的右边界为起点和终点较大x值加2
22         int right = Math.max(startX, x) + 2;
23         // 棋盘的下边界为起点和终点较大y值加2
24         int bottom = Math.max(startY, y) + 2;
25         // 以下是常规bfs套路代码
26         Queue<int[]> q = new LinkedList<>();
27         q.offer(new int[] { startX, startY });
28         boolean[][] visited = new boolean[right + 1][bottom + 1];
29         visited[startX][startY] = true;
30 
31         int res = 0;
32         while (q.size() > 0) {
33             int size = q.size();
34             while (size-- > 0) {
35                 int[] current = q.poll();
36                 if (current[0] == x & current[1] == y) {
37                     return res;
38                 }
39                 for (int[] direction : directions) {
40                     int nextX = current[0] + direction[0];
41                     int nextY = current[1] + direction[1];
42                     if (nextX <= right && nextX >= 0 && nextY <= bottom && nextY >= 0 && !visited[nextX][nextY]) {
43                         visited[nextX][nextY] = true;
44                         q.offer(new int[] { nextX, nextY });
45                     }
46                 }
47             }
48             res++;
49         }
50         return -1;
51     }
52 }

From: https://leetcode.jp/leetcode-1197-minimum-knight-moves-%e8%a7%a3%e9%a2%98%e6%80%9d%e8%b7%af%e5%88%86%e6%9e%90/