Nice solution, few suggestions:
- Duplicated code: the functions
len(memo) and len(memo[0]) are called several times. When working with a matrix is common to call m the number of rows (len(memo)) and n the number of columns (len(memo[0])). This can help to reduce the duplicated code. Another alternative, which I find more readable, is rows and cols.
- Last element of a list: instead of
memo[len(memo)-1] you can use memo[-1].
- Input validation: this input validation:
if obstacleGrid[len(memo)-1][len(memo[0])-1] == 1:
return 0
is done too late in the code, after the memo matrix is fully built. Better to move it up at the beginning of the function. BTW, with the previous suggestion it can be shortened to:
if obstacleGrid[-1][-1] == 1:
return 0
- Naming: the row is called
row in the helper function and j in the rest of the code. Same for the column. Use the same name to be consistent.
- Throwaway variables: in the initialization of memo:
memo = [[-1 for i in range(len(obstacleGrid[0]))] for j in range(len(obstacleGrid))]
the variables i and j are not used. They can be replaced with _.
- Type hints: the
helper function is missing the type hints.
- LRU cache: there is a handy annotation that does the memoization automatically, @lru_cache.
An example using @lru_cache:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
rows = len(obstacleGrid)
cols = len(obstacleGrid[0])
if obstacleGrid[-1][-1] == 1:
return 0
@lru_cache
def helper(row: int, col: int) -> int:
if 0 <= row < rows and 0 <= col < cols:
if row == rows - 1 and col == cols - 1:
return 1
if obstacleGrid[row][col] == 1:
return 0
return helper(row + 1, col) + helper(row, col + 1)
return 0
return helper(0, 0)
For dynamic programming solutions, you can have a look at the "Solution" section or "Discussion" section using tags python and dynamic programming.