[LeetCode] 1197. Minimum Knight Moves


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.

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

Example 1:

Input: x = 2, y = 1
Output: 1
Explanation: [0, 0] → [2, 1]

Example 2:

Input: x = 5, y = 5
Output: 4
Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5] 

Constraints:

  • |x| + |y| <= 300

進擊的騎士。一個坐標可以從 -infinity 延伸到 +infinity 的 無限大的 棋盤上,你的 騎士 駐扎在坐標為 [0, 0] 的方格里。騎士的走法和中國象棋中的馬相似,走 “日” 字:即先向左(或右)走 1 格,再向上(或下)走 2 格;或先向左(或右)走 2 格,再向上(或下)走 1 格。每次移動,他都可以按圖示八個方向之一前進。現在,騎士需要前去征服坐標為 [x, y] 的部落,請你為他規划路線。最后返回所需的最小移動次數即可。本題確保答案是一定存在的。

國際象棋的規則跟中國象棋類似,都是馬走日。這個題基本上就是在問你,你現在有一個馬在[0, 0],問你最少需要走幾步能走到一個目標點[x, y]。題目規定了是一定能走得到的點。我給出如下這個圖,顯示騎士可以跳的八個空格各自的坐標。

 

這是在無向圖上找最少的步數,所以思路是BFS。你需要意識到無論[x, y]在哪個象限,只要他與(0,0)的距離相等,實際在哪個象限都是等價的。所以一開始我們為了計算方便,就可以把input的這個[x, y]坐標取絕對值。這里我們為了避免走到重復的點,我們需要一個hashset記錄遍歷過的點。其他部分都是BFS的模板了。有一個細節需要注意的是雖然我們對[x, y]取了絕對值,但是並不意味着路徑中不會經過坐標值為負的點。例子就是(0, 0) -> (2, -1) -> (1, 1)。這也就是為什么代碼中26行把遍歷過的點加入hashset的時候額外判斷橫縱坐標是否都 >= -1的原因了。

另外一個優化就是為什么26行我可以限制i和j的范圍,那是因為如果你再往外跳,實際你的步數只有可能是更多。例子,比如還是從(0, 0) -> (1, 1),如果你一開始跳到(2,1),你再往比如(4,2)或者(4,0)跳,實際是沒有幫助的。

時間O(mn) 

空間O(mn)

Java實現

 1 class Solution {
 2     public int minKnightMoves(int x, int y) {
 3         int[][] dirs = new int[][] { { -1, -2 }, { -1, 2 }, { 1, -2 }, { 1, 2 }, { -2, -1 }, { -2, 1 }, { 2, -1 },
 4                 { 2, 1 } };
 5         x = Math.abs(x);
 6         y = Math.abs(y);
 7         HashSet<String> visited = new HashSet<>();
 8         Queue<int[]> queue = new LinkedList<>();
 9         queue.offer(new int[] { 0, 0 });
10         visited.add("0,0");
11 
12         int step = 0;
13         while (!queue.isEmpty()) {
14             int size = queue.size();
15             while (size-- > 0) {
16                 int[] cur = queue.poll();
17                 if (cur[0] == x && cur[1] == y) {
18                     return step;
19                 }
20 
21                 for (int[] dir : dirs) {
22                     int i = cur[0] + dir[0];
23                     int j = cur[1] + dir[1];
24                     // (0, 0) -> (2, -1) -> (1, 1)
25                     // +2的意思是多給兩個格子的空間以便於騎士跳出去再跳回來的操作
26                     if (!visited.contains(i + "," + j) && i >= -1 && j >= -1 && i <= x + 2 && j <= y + 2) {
27                         queue.offer(new int[] { i, j });
28                         visited.add(i + "," + j);
29                     }
30                 }
31             }
32             step++;
33         }
34         return -1;
35     }
36 }

 

LeetCode 題目總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM