NOTE

Unique Paths

LeetCode notes on the Unique Paths problem.

Data Structures & AlgorithmsCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. Problem Description

A robot is located at the top-left corner of an m x n grid (the starting point is marked as “Start” in the diagram below).

The robot can move only one step down or one step right at a time. It is trying to reach the bottom-right corner of the grid (marked as “Finish” in the diagram below).

How many different paths are there in total?

2. Approach

  1. Approach 1
    • DFS: reaching (m-1, n-1) means reaching the destination
    • Because movement is only right or down, the same (i,j) will not be revisited, so no set is needed to record visited positions
  2. Approach 2
    • DFS + memoization
  3. Approach 3
    • Dynamic programming

3. Implementation

3.1. DFS

func uniquePaths(m int, n int) int {
    count := 0

    uniquePathsDFS(0, 0, m, n, &count)

    return count
}

func uniquePathsDFS(row, col, m, n int, count *int) {
    if invalid(row, col, m, n) {
        return
    }

    if exceedEnd(row, col, m, n) {
        *count++
        return
    }

    uniquePathsDFS(row+1, col, m, n, count)
    uniquePathsDFS(row, col+1, m, n, count)
}

func invalid(row, col, m, n int) bool {
    
    if row < 0 || row >= m || col < 0 || col >= n {
        return true
    }

    return false
}

func exceedEnd(row, col, m, n int) bool {
    if row==m-1 && col == n-1 {
        return true
    }

    return false
}

3.2. DFS + Memoization

func uniquePaths(m int, n int) int {
    memo := make(map[string]int, 0)
    return uniquePathsDFS(0, 0, m, n, memo)
}

func uniquePathsDFS(row, col, m, n int, memo map[string]int) int {
    count, ok := memo[getKey(row, col)]
    if ok {
        return count
    }

    if invalid(row, col, m, n) {
        return 0
    }

    if exceedEnd(row, col, m, n) {
        return 1
    }

    leftCount := uniquePathsDFS(row+1, col, m, n, memo)
    rightCount := uniquePathsDFS(row, col+1, m, n, memo)

    count = leftCount + rightCount
    memo[getKey(row, col)] = count
    return count
}

func invalid(row, col, m, n int) bool {
    
    if row < 0 || row >= m || col < 0 || col >= n {
        return true
    }

    return false
}

func exceedEnd(row, col, m, n int) bool {
    if row==m-1 && col == n-1 {
        return true
    }

    return false
}

func getKey(row, col int) string {
    return fmt.Sprintf("%v:%v", row, col)
}

3.3. Dynamic Programming

func uniquePaths2(m int, n int) int {
	dp := make([][]int, m, m)
	for i := 0; i < len(dp); i++ {
		dp[i] = make([]int, n, n)
	}

	for i := 0; i < n; i++ {
		dp[0][i] = 1
	}
	for i := 0; i < m; i++ {
		dp[i][0] = 1
	}

	for i := 1; i < m; i++ {
		for j := 1; j < n; j++ {
			dp[i][j] = dp[i-1][j] + dp[i][j-1]
		}

	}
	return dp[m-1][n-1]
}

4. References

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub