There is a knight on an n x n chessboard. In a valid configuration, the knight starts at the top-left cell of the board and visits every cell on the board exactly once.
You are given an n x n integer matrix grid consisting of distinct integers from the range [0, n * n - 1] where grid[row][col] indicates that the cell (row, col) is the grid[row][col]th cell that the knight visited. The moves are 0-indexed.
Return true if grid represents a valid configuration of the knight's movements or false otherwise.
Note that a valid knight move consists of moving two squares vertically and one square horizontally, or two squares horizontally and one square vertically. The figure below illustrates all the possible eight moves of a knight from some cell.
Example 1:
Input: grid = [[0,11,16,5,20],[17,4,19,10,15],[12,1,8,21,6],[3,18,23,14,9],[24,13,2,7,22]] Output: true Explanation: The above diagram represents the grid. It can be shown that it is a valid configuration.
Example 2:
Input: grid = [[0,3,6],[5,8,1],[2,7,4]] Output: false Explanation: The above diagram represents the grid. The 8th move of the knight is not valid considering its position after the 7th move.
Constraints:
n == grid.length == grid[i].length3 <= n <= 70 <= grid[row][col] < n * ngrid are unique.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:
The brute force way to solve this problem is to try every possible path a knight could take on the board. We will check each possibility to see if it matches the given sequence of moves in the desired order. Essentially we are simulating every single possible knight tour.
Here's how the algorithm would work step-by-step:
def check_knight_tour_configuration_brute_force(grid):
rows = len(grid)
cols = len(grid[0])
move_sequence_length = rows * cols
# Possible moves for a knight
knight_moves = [
(-2, -1), (-2, 1), (-1, -2), (-1, 2),
(1, -2), (1, 2), (2, -1), (2, 1)
]
def is_valid_move(row, col):
return 0 <= row < rows and 0 <= col < cols
def solve_knight_tour(row, col, move_number):
# Check if we have completed the tour
if move_number == move_sequence_length - 1:
return True
# Try all possible knight moves
for move_row, move_col in knight_moves:
next_row = row + move_row
next_col = col + move_col
if is_valid_move(next_row, next_col) and \
grid[next_row][next_col] == move_number + 1:
# Check if next move completes tour
if solve_knight_tour(next_row, next_col, move_number + 1):
return True
return False
# The tour must start at 0
if grid[0][0] != 0:
return False
# Begin recursion to check all valid tour paths
return solve_knight_tour(0, 0, 0)The key idea is to verify that a given sequence of moves on a chessboard is a valid knight's tour. We check if each move is a valid knight's move and if we visit each square exactly once.
Here's how the algorithm would work step-by-step:
def check_knight_tour_configuration(grid):
rows = len(grid)
cols = len(grid[0])
board_size = rows * cols
if grid[0][0] != 0:
return False
visited = [[False] * cols for _ in range(rows)]
visited[0][0] = True
current_row = 0
current_col = 0
# Iterate through the sequence of moves to check validity.
for move_number in range(1, board_size):
next_row = -1
next_col = -1
# Find the next move in the sequence.
for row_index in range(rows):
for col_index in range(cols):
if grid[row_index][col_index] == move_number:
next_row = row_index
next_col = col_index
break
if next_row != -1:
break
if next_row == -1:
return False
# Check if the move is a valid knight's move.
row_diff = abs(next_row - current_row)
col_diff = abs(next_col - current_col)
if not ((row_diff == 2 and col_diff == 1) or (row_diff == 1 and col_diff == 2)):
return False
# Check if the square has already been visited.
if visited[next_row][next_col]:
return False
visited[next_row][next_col] = True
current_row = next_row
current_col = next_col
return True| Case | How to Handle |
|---|---|
| Null or empty board | Return false immediately as no tour is possible. |
| Board with dimensions 1x1 or 1x2 | Handle these small boards specifically as valid tours might exist or not, based on the starting position. |
| Knight does not start at position (0, 0) | Check if the first move is from (0,0) to ensure the given configuration starts correctly; return false if not. |
| Invalid knight moves based on board size | Ensure each move is within the bounds of the board using boundary checks. |
| Visited positions not consecutive or out of order | Verify that each knight move follows the correct sequence of the tour, using move sequence validation. |
| Board size exceeding maximum memory allocation | Consider the practical limitations on board size and memory usage, potentially limiting input dimensions based on available resources. |
| Input board contains duplicate positions | The algorithm needs to guarantee that each position is only visited once. |
| The knight tour is incomplete and doesn't cover all squares | Verify that the number of moves made in the input configuration is exactly the total number of squares in the board. |