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: 1Explanation: [0, 0] → [2, 1]
Example 2:
Input: x = 5, y = 5
Output: 4Explanation: [0, 0] → [2, 1] → [4, 2] → [3, 4] → [5, 5]
Constraints:
-300 <= x, y <= 3000 <= |x| + |y| <= 300class Solution:
def minKnightMoves(self, x: int, y: int) -> int:
# the offsets in the eight directions
offsets = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
def bfs(x, y):
visited = set()
queue = deque([(0, 0)])
steps = 0
while queue:
curr_level_cnt = len(queue)
# iterate through the current level
for i in range(curr_level_cnt):
curr_x, curr_y = queue.popleft()
if (curr_x, curr_y) == (x, y):
return steps
for offset_x, offset_y in offsets:
next_x, next_y = curr_x + offset_x, curr_y + offset_y
if (next_x, next_y) not in visited:
visited.add((next_x, next_y))
queue.append((next_x, next_y))
# move on to the next level
steps += 1
return bfs(x, y)Where is the coordinate of the target.
class Solution:
def minKnightMoves(self, x: int, y: int) -> int:
# the offsets in the eight directions
offsets = [(1, 2), (2, 1), (2, -1), (1, -2),
(-1, -2), (-2, -1), (-2, 1), (-1, 2)]
# data structures needed to move from the origin point
origin_queue = deque([(0, 0, 0)])
origin_distance = {(0, 0): 0}
# data structures needed to move from the target point
target_queue = deque([(x, y, 0)])
target_distance = {(x, y): 0}
while True:
# check if we reach the circle of target
origin_x, origin_y, origin_steps = origin_queue.popleft()
if (origin_x, origin_y) in target_distance:
return origin_steps + target_distance[(origin_x, origin_y)]
# check if we reach the circle of origin
target_x, target_y, target_steps = target_queue.popleft()
if (target_x, target_y) in origin_distance:
return target_steps + origin_distance[(target_x, target_y)]
for offset_x, offset_y in offsets:
# expand the circle of origin
next_origin_x, next_origin_y = origin_x + offset_x, origin_y + offset_y
if (next_origin_x, next_origin_y) not in origin_distance:
origin_queue.append((next_origin_x, next_origin_y, origin_steps + 1))
origin_distance[(next_origin_x, next_origin_y)] = origin_steps + 1
# expand the circle of target
next_target_x, next_target_y = target_x + offset_x, target_y + offset_y
if (next_target_x, next_target_y) not in target_distance:
target_queue.append((next_target_x, next_target_y, target_steps + 1))
target_distance[(next_target_x, next_target_y)] = target_steps + 1Where is the coordinate of the target.
class Solution:
def minKnightMoves(self, x: int, y: int) -> int:
@lru_cache(maxsize=None)
def dfs(x, y):
if x + y == 0:
# base case: (0, 0)
return 0
elif x + y == 2:
# base case: (1, 1), (0, 2), (2, 0)
return 2
else:
return min(dfs(abs(x - 1), abs(y - 2)), dfs(abs(x - 2), abs(y - 1))) + 1
return dfs(abs(x), abs(y))Where is the coordinate of the target.