一个坐标可以从 -infinity
延伸到 +infinity
的 无限大的 棋盘上,你的 骑士 驻扎在坐标为 [0, 0]
的方格里。
骑士的走法和中国象棋中的马相似,走 “日” 字:即先向左(或右)走 1 格,再向上(或下)走 2 格;或先向左(或右)走 2 格,再向上(或下)走 1 格。
每次移动,他都可以按图示八个方向之一前进。
现在,骑士需要前去征服坐标为 [x, y]
的部落,请你为他规划路线。
最后返回所需的最小移动次数即可。本题确保答案是一定存在的。
示例 1:
输入:x = 2, y = 1 输出:1 解释:[0, 0] → [2, 1]
示例 2:
输入:x = 5, y = 5 输出:4 解释:[0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5]
提示:
|x| + |y| <= 300
思路:
问最短距离一般就是BFS,
但此题需要注意棋盘无限大,所以一定要限制下一步跳的范围,不能跳的太远,不然稳定超时。
一个优化: 让x和y都变成绝对值形式,因为可以跳的八个方向都是对称的,在哪个象限并没有区别。
别的也没啥特别的,可能就是方向向量和普通的八方向方向向量有所区别。
class Solution(object):
def minKnightMoves(self, x, y):
"""
:type x: int
:type y: int
:rtype: int
"""
x, y = abs(x), abs(y)
from collections import deque
queue = deque([((0, 0), 0)])
visited = set()
visited.add((0, 0))
dx = [1, 1, 2, 2, -1, -1, -2, -2]
dy = [2, -2, 1, -1, 2, -2, 1, -1]
while queue:
cur, step = queue.popleft()
x0, y0 = cur
if [x0, y0] == [x, y]:
return step
for k in range(8):
next_x = x0 + dx[k]
next_y = y0 + dy[k]
if 0 <= next_x <= 300 and 0 <= next_y <= 300 and (next_x, next_y) not in visited:
visited.add((next_x, next_y))
queue.append(((next_x, next_y), step + 1))