diff --git a/DIRECTORY.md b/DIRECTORY.md index 150e4e61ea06..84a4c736bcf5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -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) diff --git a/backtracking/word_search.py b/backtracking/word_search.py index 8a9b2f1b5359..b6ee1211eb07 100644 --- a/backtracking/word_search.py +++ b/backtracking/word_search.py @@ -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/ @@ -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()) @@ -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 @@ -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):