62. Unique Paths

本文探讨了机器人在网格中从起点到终点的路径规划问题,通过分析递归、动态规划(DP)和备忘录(Memoization)等算法,详细解释了如何计算不同路径的数量。并提供了LeetCode上的两种解决方案实现,包括简洁的DP实现和递归加备忘录的实现。

题目

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).

How many possible unique paths are there?

我的想法

brute force
毫无悬念的超时

class Solution {
    public int uniquePaths(int m, int n) {
        return pathHelper(0, m-1, n-1, 0);
    }
    private int pathHelper(int right, int m, int n, int down) {
        if(right == m && down == n) return 1; 
        if(right > m || down > n) return 0;
        return pathHelper(right+1, m, n, down) + pathHelper(right, m, n, down+1);
    }
}

DP
居然想出来了!!!!
这里因为有向右和向下两个变量,因此定义二维数组dp[i][j]用以存储向下走i步向右走j步有多少种情况
因为一次只能走一步,并且只能是向右走或者向下走一步,因此要想达i、j到只有两种情况。dp[i][j] = dp[i-1][j] + dp[i][j-1]

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        if(m == 1 && n == 1) return 1;
        for(int k = 1; k < m; k++) {
            dp[k][0] = 1;     //给边界赋值
        }
        for(int k = 1; k < n; k++) {
            dp[0][k] = 1;     //给边界赋值
        }
        //算出前项所有结果
        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

没想出带存储的brute force该怎么写。。。。

个人觉得这道题应该可以用数学中的排列组合来做,好像是叫插空问题?

解答

leetcode solution 1: DP
别人的写法更加简练

public class Solution {
	public int uniquePaths(int m, int n) {
	    int[][] grid = new int[m][n];
	    for(int i = 0; i<m; i++){
	        for(int j = 0; j<n; j++){
	            if(i==0||j==0) //处理边界问题
	                grid[i][j] = 1;
	            else
	                grid[i][j] = grid[i][j-1] + grid[i-1][j];
	        }
	    }
	    return grid[m-1][n-1];
	}
}
//另一种更加聪明的写法
//因为需要的只是(m,n),只需要m和n中有一个变量记录下来即可
public class Solution {
    public int uniquePaths(int m, int n) {
        int[] arr = new int[m];
        for (int i = 0; i < m; i++) {
            arr[i] = 1;
        }
        for (int i = 1; i < n; i++) { //i-1的值不需要记录,只是用来推i的值
            for (int j = 1; j < m; j++) {
                arr[j] = arr[j] + arr[j-1];
            }
        }
        return arr[m-1];
    }
}

leetcode solution 2: Memoization
为何感觉与DP无异?不过是DP用的iteration这里用的recursion

class Solution {
    public int uniquePaths(int m, int n) {
        return uniquePathsHelper(m - 1, n - 1, new int[n][m]);
    }
  
    private int uniquePathsHelper(int m, int n, int[][] memo) {
        if (m < 0 || n < 0) {
            return 0;
        } 
        else if (m == 0 || n == 0) {
            return 1;
        } 
        else if (memo[n][m] > 0) {
            return memo[n][m];
        } 
        else {
            memo[n][m] = uniquePathsHelper(m - 1, n, memo) + uniquePathsHelper(m, n - 1, memo);
            return memo[n][m];
        }
    }
}
<think>我们正在处理一个TypeError,提示Solution.uniquePaths方法缺少必要位置参数'n'。这个错误通常发生在调用类的方法时,没有提供足够的位置参数。假设我们有一个类Solution,其中定义了一个方法uniquePaths,这个方法需要两个位置参数(比如m和n),但在调用时只提供了一个(比如只提供了m,而缺少n)。例如:classSolution:defuniquePaths(self,m,n):#一些代码当我们这样调用时:Solution().uniquePaths(3)#这里只提供了一个参数3,但方法需要两个参数(除了self)就会导致错误:TypeError:uniquePaths()missing1requiredpositionalargument:'n'因此,我们需要确保在调用uniquePaths时传递两个整数参数(m和n)。例如:Solution().uniquePaths(3,7)#计算3行7列的网格但是,如果这个方法是静态方法或类方法,可能不需要self,但错误信息仍然会提示缺少参数。下面我们分步骤解释如何解决:步骤1:检查方法定义确保在类中定义uniquePaths方法时,参数包括self(如果是实例方法)、m和n。例如:defuniquePaths(self,m,n):步骤2:检查调用方式在调用时,必须传入两个参数(如果是实例方法,则通过实例调用,并传入m和n;如果是静态方法,则直接传入m和n)。步骤3:注意调用方法时使用的实例如果使用类名直接调用实例方法,则需要显式传递一个实例作为self,然后再传递m和n。通常我们不会这样做,而是创建实例:sol=Solution()sol.uniquePaths(m,n)或者直接:Solution().uniquePaths(m,n)步骤4:如果方法定义为静态方法如果在定义时使用了@staticmethod装饰器,那么就不需要self,但是调用时仍然需要传入两个参数:classSolution:@staticmethoddefuniquePaths(m,n):...调用:Solution.uniquePaths(m,n)#通过类名调用步骤5:如果方法定义为类方法使用@classmethod,第一个参数是cls,然后是两个参数:classSolution:@classmethoddefuniquePaths(cls,m,n):...调用:Solution.uniquePaths(m,n)#通过类名调用步骤6:处理默认参数如果方法的某些参数有默认值,则调用时可以省略。但如果没有默认值,则必须传递。因此,针对这个错误,解决方案是:在调用uniquePaths方法时,确保传递了两个整数参数(m和n)。示例代码:正确调用实例方法:sol=Solution()result=sol.uniquePaths(3,7)或者:result=Solution().uniquePaths(3,7)正确调用静态方法(假设方法被定义为静态):result=Solution.uniquePaths(3,7)注意:在静态方法和类方法的定义中,第一个参数不是self,因此在调用时不需要传递实例或类(对于静态方法)或者只需要传递类(对于类方法,但通常通过类名调用会自动传递类)。但要注意参数个数。如果问题仍然存在,请检查方法定义和调用的地方是否一致。下面是一个完整的例子(动态规划解决网格路径问题)供参考:```pythonclassSolution:defuniquePaths(self,m,n):#创建一个二维列表用于存储到达每个网格的路径数dp=[[1]*nfor_inrange(m)]#动态规划计算路径数foriinrange(1,m):forjinrange(1,n):dp[i][j]=dp[i-1][j]+dp[i][j-1]returndp[m-1][n-1]#调用sol=Solution()print(sol.uniquePaths(3,7))#传递两个参数```如果我们尝试调用sol.uniquePaths(3),则会出现错误,因为缺少第二个参数n。因此,请确保在调用时提供了两个参数。</think> 针对TypeError: `Solution.uniquePaths()` missing required positional argument 'n' 的问题,这是由于调用方法时缺少必要的参数导致的。以下是详细分析和解决方案: ### 问题原因分析 1. **方法签名不匹配** `uniquePaths` 方法需要接收特定的位置参数(如 `m` 和 `n`),但调用时只传递了部分参数。例如: ```python class Solution: def uniquePaths(self, m: int, n: int) -> int: # 需要两个参数 ... # 错误调用(缺少n) Solution().uniquePaths(3) # ❌ 缺少第二个参数n ``` 2. **实例化与调用分离问题** 若通过类名直接调用方法而非实例方法,会遗漏实例参数: ```python # 错误调用(未实例化) Solution.uniquePaths(3, 7) # ❌ 缺少self参数 ``` 3. **方法绑定类型错误** 静态方法定义不当会导致参数传递混乱: ```python class Solution: @staticmethod def uniquePaths(m, n): # 静态方法无self参数 ... # 错误实例化调用 Solution().uniquePaths(3, 7) # ❌ 多传了self参数 ``` ### 解决方案 #### ✅ 方案1:补充完整参数(推荐) 确保传递所有必需参数: ```python class Solution: def uniquePaths(self, m: int, n: int) -> int: dp = [[1] * n for _ in range(m)] for i in range(1, m): for j in range(1, n): dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[-1][-1] # 正确调用 print(Solution().uniquePaths(3, 7)) # 输出网格路径数 ``` #### ✅ 方案2:使用默认参数 在方法定义中设置默认值避免遗漏: ```python class Solution: def uniquePaths(self, m: int, n: int = 1): # n默认值为1 if n == 1: # 边界情况处理 return 1 ... # 灵活调用 Solution().uniquePaths(3) # 使用默认n=1 Solution().uniquePaths(3, 7) # 显式指定n ``` #### ✅ 方案3:正确使用静态方法 统一静态方法的调用方式: ```python class Solution: @staticmethod def uniquePaths(m: int, n: int) -> int: ... # 通过类名调用(无需实例化) Solution.uniquePaths(3, 7) # ✅ ``` ### 关键检查点 1. 方法定义中参数数量(包括 `self`) 2. 调用时实参与形参匹配度 3. 方法类型(实例方法/静态方法)与调用方式的一致性 > 路径计数问题中,动态规划是常见解法:通过二维数组存储中间状态,时间复杂度为 $O(m \times n)$,空间复杂度可优化至 $O(n)$[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值