題目:5073. 進擊的騎士java
一個座標能夠從 -infinity
延伸到 +infinity
的 無限大的 棋盤上,你的 騎士 駐紮在座標爲 [0, 0]
的方格里。web
騎士的走法和中國象棋中的馬類似,走 「日」 字:即先向左(或右)走 1 格,再向上(或下)走 2 格;或先向左(或右)走 2 格,再向上(或下)走 1 格。算法
每次移動,他均可以按圖示八個方向之一前進。數組
如今,騎士須要前去征服座標爲 [x, y] 的部落,請你爲他規劃路線。svg
最後返回所需的最小移動次數便可。本題確保答案是必定存在的。spa
輸入:x = 2, y = 1 輸出:1 解釋:[0, 0] → [2, 1]
輸入:x = 5, y = 5 輸出:4 解釋:[0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5]
|x| + |y| <= 300
比較愚笨的辦法就是用 寬度優先搜索(BFS) 算法走到目標點爲止。我採用的也是這種算法。至於第一名的用的算法在下實在是看不懂,姑且先放着。我在CSDN論壇發的討論第一名寫的代碼的帖子。.net
很明顯,棋盤是對稱的。直接將目標點座標取絕對值,調整到第一象限或 X
軸或 Y
軸。code
而後只在第一象限用BFS算得結果。xml
起點(0,0)是特殊點,直接返回 0。blog
點(1,1)也是特殊點,由於只在第一象限的話到達(1,1)至少要 4 步,可是若是能夠經過其餘象限的話,只須要 2 步便可到達(1,1)。
用二維數組 board[x + 3][y + 3]
表示到達點(r,c)的最少步數。
到達一個點後,若是合法,則步數等於上一個點的步數加 1。若是是目標點,直接返回步數,不然將座標入隊列。
時間複雜度: 在下無能爲力
空間複雜度: 在下仍是無能爲力
class Solution { public int minKnightMoves( int x, int y) { x = Math.abs(x);// 調整到第一象限 y = Math.abs(y); if (x + y == 0) {// 起點(0,0) return 0; } if (x == 1 && y == 1) {// 此算法是沒法計算點(1,1)的最少步數 return 2; } int m = x + 3; int n = y + 3; int[][] board = new int[m][n]; int[] dx = { 2, 1, -1, -2, -2, -1, 1, 2 }; int[] dy = { 1, 2, 2, 1, -1, -2, -2, -1 }; Queue<int[]> queue = new LinkedList<>(); queue.add(new int[] { 0, 0 }); while (!queue.isEmpty()) { int[] cur = queue.poll();// 出隊列 for (int i = 0; i < 8; ++i) { int r = cur[0] + dx[i]; int c = cur[1] + dy[i]; if (r < 0 || r >= m || c < 0 || c >= n) {// 越界 continue; } if (r + c == 0) {// 回到了起點 continue; } if (board[r][c] == 0) {// 未訪問過當前點 board[r][c] = board[cur[0]][cur[1]] + 1; if (r == x && c == y) {// 當前點就是目標點 return board[r][c];// 返回結果 } queue.add(new int[] { r, c });// 不是目標點,入隊列 } } } return -1; } }