You are given a square board
of characters. You can move on the board starting at the bottom right square marked with the character 'S'
.
You need to reach the top left square marked with the character 'E'
. The rest of the squares are labeled either with a numeric character 1, 2, ..., 9
or with an obstacle 'X'
. In one move you can go up, left or up-left (diagonally) only if there is no obstacle there.
Return a list of two integers: the first integer is the maximum sum of numeric characters you can collect, and the second is the number of such paths that you can take to get that maximum sum, taken modulo 10^9 + 7
.
In case there is no path, return [0, 0]
.
Example 1:
Input: board = ["E23","2X2","12S"] Output: [7,1]
Example 2:
Input: board = ["E12","1X1","21S"] Output: [4,2]
Example 3:
Input: board = ["E11","XXX","11S"] Output: [0,0]
Constraints:
2 <= board.length == board[i].length <= 100
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:
We want to find the best path to the starting point on a game board and the maximum score we can achieve on that path. The brute force approach is like trying every possible way to move from the end to the start and figuring out the score for each of those paths.
Here's how the algorithm would work step-by-step:
def number_of_paths_with_max_score_brute_force(board):
rows = len(board)
cols = len(board[0])
max_score = 0
number_of_paths = 0
def is_valid(row_index, col_index):
return 0 <= row_index < rows and 0 <= col_index < cols and board[row_index][col_index] != 'X'
def find_paths(row_index, col_index, current_score, path_count):
nonlocal max_score, number_of_paths
# Base case: Reached the starting point
if row_index == 0 and col_index == 0:
if current_score > max_score:
max_score = current_score
number_of_paths = path_count
elif current_score == max_score:
number_of_paths += path_count
return
# Check for valid moves up and left
possible_moves = []
if is_valid(row_index - 1, col_index):
possible_moves.append((row_index - 1, col_index))
if is_valid(row_index, col_index - 1):
possible_moves.append((row_index, col_index - 1))
# No possible moves means a dead end
if not possible_moves:
return
# Calculate the current cell value to add to score
current_cell_value = 0
if board[row_index][col_index] != 'E':
current_cell_value = int(board[row_index][col_index])
# Explore all possible paths using recursion
for next_row_index, next_col_index in possible_moves:
find_paths(next_row_index, next_col_index, current_score + current_cell_value, path_count)
# Start from the end point
find_paths(rows - 1, cols - 1, 0, 1)
# Modulo operation to prevent overflow, required by the prompt
return [max_score, number_of_paths % (10**9 + 7)]
We want to find the best possible score and the number of ways to achieve that score when moving from the end to the start of a board. We use a clever trick to remember the best score and number of paths to reach each spot, avoiding redundant calculations.
Here's how the algorithm would work step-by-step:
def number_of_paths_with_max_score(board):
board_size = len(board)
score_dp = [[0] * board_size for _ in range(board_size)]
paths_dp = [[0] * board_size for _ in range(board_size)]
paths_dp[board_size - 1][board_size - 1] = 1
for row_index in range(board_size - 1, -1, -1):
for column_index in range(board_size - 1, -1, -1):
if board[row_index][column_index] == 'X':
continue
if row_index == board_size - 1 and column_index == board_size - 1:
score_dp[row_index][column_index] = 0
continue
max_score = -1
number_of_paths = 0
#Check the 'down' direction
if row_index + 1 < board_size and board[row_index + 1][column_index] != 'X':
if score_dp[row_index + 1][column_index] > max_score:
max_score = score_dp[row_index + 1][column_index]
number_of_paths = paths_dp[row_index + 1][column_index]
elif score_dp[row_index + 1][column_index] == max_score:
number_of_paths = (number_of_paths + paths_dp[row_index + 1][column_index]) % 1000000007
#Check the 'right' direction
if column_index + 1 < board_size and board[row_index][column_index + 1] != 'X':
if score_dp[row_index][column_index + 1] > max_score:
max_score = score_dp[row_index][column_index + 1]
number_of_paths = paths_dp[row_index][column_index + 1]
elif score_dp[row_index][column_index + 1] == max_score:
number_of_paths = (number_of_paths + paths_dp[row_index][column_index + 1]) % 1000000007
#Check the 'diagonal' direction
if row_index + 1 < board_size and column_index + 1 < board_size and board[row_index + 1][column_index + 1] != 'X':
if score_dp[row_index + 1][column_index + 1] > max_score:
max_score = score_dp[row_index + 1][column_index + 1]
number_of_paths = paths_dp[row_index + 1][column_index + 1]
elif score_dp[row_index + 1][column_index + 1] == max_score:
number_of_paths = (number_of_paths + paths_dp[row_index + 1][column_index + 1]) % 1000000007
if max_score != -1:
#Add the current cell value to the path
if board[row_index][column_index] != 'S':
score_dp[row_index][column_index] = int(board[row_index][column_index]) + max_score
else:
score_dp[row_index][column_index] = max_score
#The number of paths equals to the value we have computed
paths_dp[row_index][column_index] = number_of_paths
# If no path exists return 0
if paths_dp[0][0] == 0:
return [0, 0]
# Return the score and the number of paths
else:
return [score_dp[0][0], paths_dp[0][0] % 1000000007]
Case | How to Handle |
---|---|
Null or empty board input | Return [0, 0] if the board is null or empty as there are no paths or scores. |
Board with only one cell (start or end) | If the board has only one cell and it's 'E', the score is 0 and there's one path; otherwise, score and path are both 0. |
Board with no path to the end ('E') | If there is no path from the start to 'E', the score and number of paths should both be zero. |
Board containing obstacles ('X') that block all paths | If all possible paths are blocked by 'X', the result should be score 0 and 0 paths. |
Large board size to check for time complexity issues. | Use dynamic programming to optimize the solution, achieving a time complexity of O(N*N) where N is the size of the board. |
Board with large numerical values leading to integer overflow during score calculation. | Use modulo operator to avoid integer overflow during score calculation, taking the modulo by 10^9 + 7 as specified. |
Multiple paths with the same maximum score | The solution should count and return the number of distinct paths leading to the maximum score. |
Board only contains number characters and 'E' and 'X'. | The code should throw an exception when an invalid character occurs on the board. |