带障碍的不同路径数
Unique Paths with Obstacles
开始编码某资金分配引擎按双轴时序网格规划再平衡:行表示某一压力维度(例如总杠杆档位)逐级加深,列表示另一维度(例如行业集中度档位)逐级加深。每一步策略只能让某一轴再紧一档:加深行方向(向下走)或加深列方向(向右走)。某些 (r, c) 联合状态是不可行的——可能撞上风控硬上限或监管红线——这些状态记为 grid[r][c] = 1;可行状态记为 0。从最温和的联合状态 (0, 0) 出发,能走到右下角 (R-1, C-1) 的、不同的可行升级路径有多少条?这个计数就是优化器后续按盈亏、容量或换手率打分时的可行方案空间大小。
请实现 solution(grid: list[list[int]]) -> int。返回从 (0, 0) 到 (R-1, C-1)、只走右/下、且不踩 1 格子的不同路径数,对 1_000_000_007 取模(原始计数可能超出任何定宽整数)。如果起点或终点本身就是障碍,返回 0。在每次 dp 累加时取模;小于模数的答案原样返回(因此下面的小例子是精确值)。
示例 1——LeetCode 63 教科书示例:solution([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) 返回 2。无障碍 3x3 有 C(4, 2) = 6 条单调路径;中心 (1, 1) 的障碍正好吞掉了所有穿过它的 4 条,剩下两条「贴边」路径:上行→右列,以及左列→下行。
示例 2——终点被堵:solution([[0, 0, 0], [0, 0, 1]]) 返回 0。终点 (1, 2) 本身就是障碍,不存在合法路径。同理起点被堵:solution([[1, 0], [0, 0]]) 返回 0。DP 要么在初值就把 dp[0][0] 置零(起点堵),要么在最后一格强制 dp[R-1][C-1] = 0(终点堵)。
示例 3——单通道无绕行:solution([[0, 1, 0, 0]]) 返回 0。只有一行时路径被迫穿过每一列,通道上任何位置的障碍都把它截断。反之,没有障碍的 1xN 单行或 Nx1 单列总是返回 1(路径唯一)。
Practical context
这就是 LeetCode 63,「带可行性约束的路径计数」的经典模板。它在不同包装下反复出现:优化里的可行域网格游走、组合学里的格点路径、受约束 DAG 上的单调路由——同一份递推靠一行修改(「障碍格归零,否则加前驱」)就能通吃。结构上的洞察远不止于路径:滚动数组上「先读后写」的同款写法,正是 0/1 背包和编辑距离把 2D DP 压成 O(C) 内存的钥匙。每当问题问到「在某种受约束的时序里有多少条单调可行轨迹」、再考虑后续的目标函数前,从业者第一反应就是套这个骨架。
约束条件
- 1 ≤ R, C,其中 R = len(grid)、C = len(grid[0])
- R ≤ 100 且 C ≤ 100
- 所有行长度都为 C(矩形网格)
- grid[i][j] ∈ {0, 1};0 表示空地,1 表示障碍
- 允许的移动:向右 (r, c) → (r, c+1) 或向下 (r, c) → (r+1, c)。不允许斜向、不允许向上/向左。
- 路径从 (0, 0) 出发,到 (R-1, C-1) 结束;两端都必须畅通才可能存在路径
- 路径数可能极大(100x100 全空时 C(198, 99) ≈ 9.06e58),因此返回路径数对 1_000_000_007 取模的结果。在每次 dp 累加时取模;小于模数的答案原样返回。
样例
Case 1 · 1x1 clear: trivial single-cell start equals end
输入: [[[0]]]
期望: 1
R=C=1 且无障碍:起点就是终点,路径数为 1。这是 LC63 的最小可行情形。
Case 2 · LC63 textbook 3x3 with center obstacle
输入: [[[0,0,0],[0,1,0],[0,0,0]]]
期望: 2
LeetCode 63 教科书示例:3x3 中央 (1,1) 是障碍。一个干净的 3x3 共有 C(4,2)=6 条单调路径,其中经过中心的路径恰好有 4 条被禁掉,剩下 2 条:沿上行→右下角,或沿左列→下行。DP 在 (1,1) 处置零阻断了所有穿过它的路径。
Case 3 · all-clear 4x4: pure binomial coefficient
输入: [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]]
期望: 20
无障碍时退化为经典的「unique paths」:路径数等于 C(R+C-2, R-1) = C(6,3) = 20。DP 把帕斯卡三角形铺到了网格上——每格的值就是它对应位置的二项式系数。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · 1x1 clear: trivial single-cell start equals end
输入: [[[0]]]
期望: 1
R=C=1 且无障碍:起点就是终点,路径数为 1。这是 LC63 的最小可行情形。
Case 2 · LC63 textbook 3x3 with center obstacle
输入: [[[0,0,0],[0,1,0],[0,0,0]]]
期望: 2
LeetCode 63 教科书示例:3x3 中央 (1,1) 是障碍。一个干净的 3x3 共有 C(4,2)=6 条单调路径,其中经过中心的路径恰好有 4 条被禁掉,剩下 2 条:沿上行→右下角,或沿左列→下行。DP 在 (1,1) 处置零阻断了所有穿过它的路径。
Case 3 · all-clear 4x4: pure binomial coefficient
输入: [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]]
期望: 20
无障碍时退化为经典的「unique paths」:路径数等于 C(R+C-2, R-1) = C(6,3) = 20。DP 把帕斯卡三角形铺到了网格上——每格的值就是它对应位置的二项式系数。