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 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:
-300 <= x, y <= 300
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine a knight on a chessboard trying to reach a destination. The brute force approach is like trying every possible sequence of knight moves until we find one that gets us there. We keep track of the number of moves it takes for each sequence and pick the shortest one.
Here's how the algorithm would work step-by-step:
def minimum_knight_moves_brute_force(target_row, target_column):
possible_moves = [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]
queue = [((0, 0), 0)]
visited = set()
visited.add((0, 0))
while queue:
(current_row, current_column), moves = queue.pop(0)
if current_row == target_row and current_column == target_column:
return moves
for row_change, column_change in possible_moves:
new_row = current_row + row_change
new_column = current_column + column_change
# Avoid cycles and redundant paths
if (new_row, new_column) not in visited:
visited.add((new_row, new_column))
queue.append(((new_row, new_column), moves + 1))
return -1 # Should not reach here, but good to have a return
The best way to find the fewest knight moves is to explore possibilities in order of their distance from the start, like ripples in a pond. We use a method that guarantees we find the shortest path first, stopping when we reach the target.
Here's how the algorithm would work step-by-step:
from collections import deque
def minimum_knight_moves(target_x, target_y):
queue = deque([(0, 0, 0)])
visited = set()
visited.add((0, 0))
# Possible knight moves.
knight_moves = [(1, 2), (1, -2), (-1, 2), (-1, -2),
(2, 1), (2, -1), (-2, 1), (-2, -1)]
while queue:
current_x, current_y, moves = queue.popleft()
if current_x == target_x and current_y == target_y:
return moves
for move_x, move_y in knight_moves:
next_x = current_x + move_x
next_y = current_y + move_y
# Only process unvisited squares
if (next_x, next_y) not in visited:
# We add to visited before the queue.
visited.add((next_x, next_y))
queue.append((next_x, next_y, moves + 1))
Case | How to Handle |
---|---|
Target is at the origin (0, 0) | Return 0 immediately as no moves are needed. |
Target coordinates are far from the origin (large x, y) | BFS scales relatively well but might require significant memory; consider iterative deepening A* search or heuristic optimization for extremely large coordinates. |
Target coordinates are negative (x < 0 or y < 0) | Leverage the symmetry of the knight's movement to transform negative coordinates to positive ones by taking absolute values or reflecting across axes to reduce redundant calculations. |
Coordinates are close to origin like (1,1) or (2,0) | BFS will find the optimal solution quickly since it explores neighbors level by level. |
Integer overflow for extremely large coordinates (x,y) during distance calculation if not handled properly | Use appropriate data types (e.g., long or long long in C++, Python integers) to prevent potential integer overflows during BFS calculations or when determining visited nodes bounds. |
The knight can return to a visited position, creating cycles | Maintain a 'visited' set or map to avoid re-exploring already visited positions, preventing infinite loops and ensuring optimal path finding. |
Memory exhaustion due to extremely large exploration space | Implement iterative deepening BFS (IDBFS) or A* search with a suitable heuristic (e.g. Manhattan distance) to prioritize promising paths and limit memory usage. |
Target x or y coordinate are non-integer numbers | Cast the input to integer, or report invalid input. |