func uniquePaths(m int, n int) int {
    // return func1(m-1, n-1, 0, 0);
    // return func2(m, n);
    return func4(m, n);
}
//  1. recursive
func func1(m int, n int, i int, j int) int {
    if i < 0 || m < i || j < 0 || n < j {
        return 0;
    }
    if m == i && n == j {
        return 1;
    }
    return func1(m, n, i+1, j) + func1(m, n, i, j+1);
}
//  2. recursive + memo
func func2(m int, n int) int {
    memo := make([][]int, m);
    for i := 0; i < m; i++ {
        memo[i] = make([]int, n);
        for j := 0; j < n; j++ {
            memo[i][j] = -1;
        }
    }
    return helper2(m-1, n-1, 0, 0, memo);
}
func helper2(m int, n int, i int, j int, memo [][]int) int {
    if i < 0 || m < i || j < 0 || n < j {
        return 0;
    }
    if m == i && n == j {
        return 1;
    }
    if memo[i][j] != -1 {
        return memo[i][j];
    }
    memo[i][j] = helper2(m, n, i+1, j, memo) + helper2(m, n, i, j+1, memo);
    return memo[i][j];
}
//  3. iterative + memo, pass
//  4. iterative + 2N variables
func func4(m int, n int) int {
    memo := make([][]int, 2);
    for i := 0; i < 2; i++ {
        memo[i] = make([]int, n);
        for j := 0; j < n; j++ {
            memo[i][j] = 0;
        }
    }
    memo[(m-1)%2][n-1] = 1;
    for i := m-1; i >= 0; i-- {
        for j := n-1; j >= 0; j-- {
            if i == m-1 && j == n-1 {
                continue;
            }
            memo[i%2][j] = 0;
            if j+1 < n {
                memo[i%2][j] += memo[i%2][j+1];
            }
            if i+1 < m {
                memo[i%2][j] += memo[(i+1)%2][j];
            }
        }
    }
    // for i := 0; i < 2; i++ {
    //  for j := 0; j < n; j++ {
    //      fmt.Println(i, j, memo[i][j]);
    //  }
    // }
    return memo[0][0];
}