Python技术迷

这四个offer四选一,你们觉得选哪个比较好?

刚刷到这个四选一,给我看精神了。

一个是去车企,月到手四万档,年底还有一堆薪,干自动驾驶;一个是去上海中学当数学老师,月薪低一截,但有安家费,稳定感直接拉满;另外俩更猛,一个大模型推理,一个机器人感知,钱也都在四万多,年包看着很香。

这题表面是选offer,其实是选命。

Image

想冲钱和技术上限,那肯定盯着AI和机器人,节奏快,压力也别装看不见。想要牌子和产业落地,车企也不差,自动驾驶这几年一直卷。可要是家里想稳,自己也不想天天被项目追着跑,上海中学那个反而最耐看。

程序员老鬼看完就一个感觉:年轻敢卷选DeepSeek或者宇树,想活得像个人,老师真不丢人。

今日算法题

出界的路径数,别一上来就 DFS 硬搜

这题最容易写歪的地方,不是不会走四个方向,而是把它当成普通迷宫题。

普通迷宫是问你能不能走到某个格子。 这题问的是:球从某个格子出发,最多走 maxMove 步,有多少种走法会冲出边界。

注意,是“冲出去”的那一脚就算一次路径。

比如球在 (0, 0),往上走,出界,算 1 条;往左走,出界,也算 1 条。它不是等所有步数走完再统计,而是每一步都可能产生答案。

我第一次看这题,第一反应也会想递归:

dfs(row, col, rest)

但这地方我一般会多看一眼数据范围。只要步数稍微大一点,递归分叉就是 4^maxMove,缓存不加基本没法看。加缓存当然能过,但这题用动态规划写起来更稳,也更像线上那种“按轮次滚状态”的处理方式。

状态不用搞复杂。

dp[r][c] 表示当前这一步之前,球在 (r, c) 的路径数。

每走一步,就从当前所有格子往四个方向扩散:

  • 如果新位置还在网格里,累加到下一轮;
  • 如果新位置出界,答案加上当前格子的路径数。

这就完了。

关键代码如下:

classSolution:
deffindPaths(
        self,
        m: int,
        n: int,
        maxMove: int,
        startRow: int,
        startColumn: int
    )
 -> int:

        mod = 1_000_000_007

        cur = [[0] * n for _ in range(m)]
        cur[startRow][startColumn] = 1

        ans = 0
        dirs = ((1, 0), (-1, 0), (0, 1), (0, -1))

for _ in range(maxMove):
            nxt = [[0] * n for _ in range(m)]

for r in range(m):
for c in range(n):
                    ways = cur[r][c]
if ways == 0:
continue

for dr, dc in dirs:
                        nr, nc = r + dr, c + dc

if nr < 0or nr >= m or nc < 0or nc >= n:
                            ans = (ans + ways) % mod
else:
                            nxt[nr][nc] = (nxt[nr][nc] + ways) % mod

            cur = nxt

return ans

这段代码里有个细节我会保留:

if ways == 0:
continue

不是为了显得高级,就是少跑点空格子。很多时候 DP 表一开始很稀,尤其 maxMove 不大的时候,大量格子根本到不了,硬扫四个方向没必要。

再拿一个小例子过一下。

m = 2
n = 2
maxMove = 2
startRow = 0
startColumn = 0

第一步,从左上角出发:

往上出界,答案 +1。 往左出界,答案 +1。 往下到 (1,0)。 往右到 (0,1)。

第二步,球可能在 (1,0) 和 (0,1)。

从 (1,0) 往下出界,往左出界,各加 1。 从 (0,1) 往上出界,往右出界,各加 1。

最后答案就是 6。

这题还有一个坑,很多人会把 maxMove 理解成“必须走满这么多步”。其实不是,题目说的是最多走这么多步。第一步出界就已经算了,后面不用管这条路径了。

所以答案必须在每一轮扩散时累加,而不是等循环结束以后再看哪些点在边界上。

边界点也不是答案。 从边界点走出去的那一步,才是答案。

时间复杂度是:

O(maxMove * m * n * 4)

四个方向可以当常数看,实际就是 maxMove * m * n。

空间复杂度是:

O(m * n)

因为只保留当前轮和下一轮,不需要把所有步数的状态都存下来。

这题写 DFS + 记忆化也可以,但 DP 的好处是顺序很清楚:一轮一轮推,路径什么时候出界,答案什么时候增加,不容易把“最多走几步”和“正好走几步”搞混。

这种题别急着套模板,先盯住一句话:出界发生在移动那一刻。 代码就顺了。