I have a rectangle of . (platforms) and # (obstacles). I can start at any platform in the top row and go to the left, right or down to another platform. I cannot visit a platform twice. I need to find the longest path from the top row to the bottom row.
Example input:
#.....#... #......... ..#.....#. ..#....#.# ..###.#..# Example output:
21 Explanation:
#54321#... #6789abc.. ..#hgfed#. ..#ijk.#.# ..###l#..# I marked the longest path as a sequence 123456789abcdefghijkl, which includes 21 platforms.
I tried to use Depth-First-Search with memoization.
Here is the code:
def longest_path(grid): if not grid or not grid[0]: return 0 memo = {} def dfs(row, col): memoKey = [row, col] if col == 0: memoKey.append(('#', grid[row][1])) elif col == len(grid[0]) - 1: memoKey.append((grid[row][col - 1], '#')) else: memoKey.append((grid[row][col - 1], grid[row][col + 1])) memoKey = tuple(memoKey) if memoKey in memo: return memo[memoKey] max_path = 0 directions = [] if row == len(grid) - 1: # Reached the bottom directions = [(0, 1), (0, -1)] # Right, Left else: directions = [(0, 1), (1, 0), (0, -1)] # Right, Down, Left # Mark the current cell as visited grid[row][col] = '#' for dr, dc in directions: new_row, new_col = row + dr, col + dc if 0 <= new_row < len(grid) and 0 <= new_col < len(grid[0]) and grid[new_row][new_col] == '.': path_length = dfs(new_row, new_col) max_path = max(max_path, 1 + path_length) # After exploring all directions, backtrack by marking the cell as unvisited grid[row][col] = '.' memo[memoKey] = max_path return max_path max_path = 0 for col in range(len(grid[0])): if grid[0][col] == '.': max_path = max(max_path, dfs(0, col)) return max_path + 1 My memo keys might seem weird. That is because I store the state of the cell to the left and right to prevent visiting a platform twice.
Example for why you need this:
Input:
##.. .... .... Imagine starting at (0, 3) and going to (1, 3). Then you calculate the longest path from (1, 3), and it turns out to be 8, by going to (1, 0), then to (2, 0), and to (2, 3). You memoize this using (1, 3) as the key. Then, you try starting at (0, 2) and going down and to the right. Then you take the memoized value of 8, and it results in a path of length 10. However, this results in visiting (1, 2) twice.
That algorithm was too inefficient for my goals. Suggestions about another algorithm or an optimization of the existing one are appreciated.