Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,7 @@
* [Doppler Frequency](physics/doppler_frequency.py)
* [Escape Velocity](physics/escape_velocity.py)
* [Grahams Law](physics/grahams_law.py)
* [Hamiltonian](physics/hamiltonian.py)
* [Horizontal Projectile Motion](physics/horizontal_projectile_motion.py)
* [Hubble Parameter](physics/hubble_parameter.py)
* [Ideal Gas Law](physics/ideal_gas_law.py)
Expand Down
149 changes: 118 additions & 31 deletions backtracking/word_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
Result:
True

Implementation notes: Use backtracking approach.
Implementation notes: Use a backtracking approach.
At each point, check all neighbors to try to find the next letter of the word.

leetcode: https://leetcode.com/problems/word-search/
Expand Down Expand Up @@ -53,7 +53,7 @@ def exits_word(
visited_points_set: set[int],
) -> bool:
"""
Return True if it's possible to search the word suffix
Return True if it's possible to search for the word suffix
starting from the word_index.

>>> exits_word([["A"]], "B", 0, 0, 0, set())
Expand Down Expand Up @@ -88,13 +88,122 @@ def exits_word(
return False


def validate_board_and_word(board: list[list[str]], word: str) -> None:
"""
>>> board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]
>>> validate_board_and_word(board, "ABCCED")
>>> validate_board_and_word(board, "SEE")
>>> validate_board_and_word(board, "ABCB")
>>> validate_board_and_word([["A"]], "A")
>>> validate_board_and_word(
... [["B", "A", "A"], ["A", "A", "A"], ["A", "B", "A"]], "ABB"
... )
>>> validate_board_and_word([["A"]], 123)
Traceback (most recent call last):
...
ValueError: The word parameter should be a string of length greater than 0.
>>> validate_board_and_word([["A"]], "")
Traceback (most recent call last):
...
ValueError: The word parameter should be a string of length greater than 0.
>>> validate_board_and_word([[]], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non-empty matrix of single-character strings.
>>> validate_board_and_word([], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non-empty matrix of single-character strings.
>>> validate_board_and_word([["A"], [21]], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non-empty matrix of single-character strings.
"""

# Validate board
msg = "The board should be a non-empty matrix of single-character strings."
if not board or not isinstance(board, list):
raise ValueError(msg)

for row in board:
if not row or not isinstance(row, list):
raise ValueError(msg)

for item in row:
if not item or not isinstance(item, str):
raise ValueError(msg)

# Validate word
if not isinstance(word, str) or len(word) == 0:
msg = "The word parameter should be a string of length greater than 0."
raise ValueError(msg)


def get_word_path(board: list[list[str]], word: str) -> list[tuple[int, int]] | None:
"""
Return the path of the word in the board if it exists; otherwise, return None.

>>> board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]
>>> get_word_path(board, "ABCCED")
[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1)]
>>> get_word_path(board, "SEE")
[(1, 3), (2, 3), (2, 2)]
>>> get_word_path(board, "ABCB") is None
True
>>> get_word_path([["A"]], 123)
Traceback (most recent call last):
...
ValueError: The word parameter should be a string of length greater than 0.
"""
validate_board_and_word(board, word)
rows, cols = len(board), len(board[0])

def backtrack(
r: int,
c: int,
index: int,
path: list[tuple[int, int]],
visited: set[tuple[int, int]],
) -> list[tuple[int, int]] | None:
if board[r][c] != word[index]:
return None

path.append((r, c))
visited.add((r, c))

if index == len(word) - 1:
return path.copy()

directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited:
result = backtrack(nr, nc, index + 1, path, visited)
if result:
return result

path.pop()
visited.remove((r, c))
return None

for i in range(rows):
for j in range(cols):
result = backtrack(i, j, 0, [], set())
if result:
return result

return None


def word_exists(board: list[list[str]], word: str) -> bool:
"""
>>> word_exists([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCCED")
>>> board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]
>>> word_exists(board, "ABCCED")
True
>>> word_exists([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "SEE")
>>> word_exists(board, "SEE")
True
>>> word_exists([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCB")
>>> word_exists(board, "ABCB")
False
>>> word_exists([["A"]], "A")
True
Expand All @@ -111,40 +220,18 @@ def word_exists(board: list[list[str]], word: str) -> bool:
>>> word_exists([[]], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non empty matrix of single chars strings.
ValueError: The board should be a non-empty matrix of single-character strings.
>>> word_exists([], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non empty matrix of single chars strings.
ValueError: The board should be a non-empty matrix of single-character strings.
>>> word_exists([["A"], [21]], "AB")
Traceback (most recent call last):
...
ValueError: The board should be a non empty matrix of single chars strings.
ValueError: The board should be a non-empty matrix of single-character strings.
"""

# Validate board
board_error_message = (
"The board should be a non empty matrix of single chars strings."
)

validate_board_and_word(board, word)
len_board = len(board)
if not isinstance(board, list) or len(board) == 0:
raise ValueError(board_error_message)

for row in board:
if not isinstance(row, list) or len(row) == 0:
raise ValueError(board_error_message)

for item in row:
if not isinstance(item, str) or len(item) != 1:
raise ValueError(board_error_message)

# Validate word
if not isinstance(word, str) or len(word) == 0:
raise ValueError(
"The word parameter should be a string of length greater than 0."
)

len_board_column = len(board[0])
for i in range(len_board):
for j in range(len_board_column):
Expand Down
Loading