You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Python实现支持可逆使用的网格严格递增路径查找

解决网格中从左上到右下的严格递增路径问题

嘿,我来帮你搞定这个问题!刚好之前做过类似的路径查找需求,下面给你两种实用的Python解决方案,都支持可逆使用(也就是可以重复调用,处理不同网格或者同一网格多次),完全符合你的要求。

首先先明确下核心规则:只能上下左右移动,目标单元格值必须严格大于当前,要找出从左上角到右下角的所有有效路径。

方案1:递归回溯 + 缓存优化(直观易读)

递归回溯是最直接的思路——从起点出发,遍历所有合法的下一步,直到走到终点,记录所有有效路径。为了支持复用,我把逻辑封装成了无状态函数,还加了缓存避免重复计算。

这里有个关键优化:因为路径是严格递增的,所以绝对不会走回头路(回头的单元格值肯定比当前小),所以不需要额外维护visited集合,省了不少事!

from functools import lru_cache
from typing import List

def find_valid_paths(grid: List[List[int]]) -> List[List[int]]:
    # 处理空网格的边界情况
    if not grid or not grid[0]:
        return []
    
    rows, cols = len(grid), len(grid[0])
    end_i, end_j = rows - 1, cols - 1
    start_val, end_val = grid[0][0], grid[end_i][end_j]
    
    # 如果终点值不大于起点,直接返回空
    if end_val <= start_val:
        return []
    
    # 递归函数:返回从(i,j)到终点的所有路径
    @lru_cache(maxsize=None)
    def dfs(i: int, j: int) -> List[List[int]]:
        current_val = grid[i][j]
        # 到达终点,返回仅包含终点的路径
        if i == end_i and j == end_j:
            return [[current_val]]
        
        paths = []
        # 遍历四个方向
        for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            ni, nj = i + di, j + dj
            # 检查是否在网格内,且目标值严格更大
            if 0 <= ni < rows and 0 <= nj < cols and grid[ni][nj] > current_val:
                # 把当前值加到每条子路径的开头
                for sub_path in dfs(ni, nj):
                    paths.append([current_val] + sub_path)
        
        return paths
    
    # 从起点开始递归
    return dfs(0, 0)

测试示例

grid = [[1,4,3], [5,6,7]]
print(find_valid_paths(grid))
# 输出:[[1,4,6,7], [1,5,6,7]],完美匹配你的预期!

为什么支持可逆使用?

  • 函数是无状态的,每次传入不同网格都会独立计算,不会互相干扰
  • lru_cache会缓存每个位置到终点的路径集合,如果同一网格被多次调用,第二次直接读缓存,速度更快
  • 输入输出清晰,随时可以调用

方案2:迭代式DFS(避免递归栈溢出)

如果你的网格特别大(比如1000x1000),递归可能会触发栈溢出。这时候迭代式DFS就更靠谱了,思路和递归一样,只是用栈来模拟递归过程。

from typing import List

def find_valid_paths_iterative(grid: List[List[int]]) -> List[List[int]]:
    if not grid or not grid[0]:
        return []
    
    rows, cols = len(grid), len(grid[0])
    end_i, end_j = rows - 1, cols - 1
    start_val, end_val = grid[0][0], grid[end_i][end_j]
    
    if end_val <= start_val:
        return []
    
    # 栈元素:(当前行, 当前列, 当前路径)
    stack = [(0, 0, [start_val])]
    valid_paths = []
    
    while stack:
        i, j, current_path = stack.pop()
        # 到达终点,加入结果列表
        if i == end_i and j == end_j:
            valid_paths.append(current_path)
            continue
        
        current_val = grid[i][j]
        # 遍历四个方向(栈是后进先出,想和递归顺序一致的话可以调整方向顺序)
        for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            ni, nj = i + di, j + dj
            if 0 <= ni < rows and 0 <= nj < cols and grid[ni][nj] > current_val:
                # 复制当前路径并添加新值,压入栈
                new_path = current_path.copy()
                new_path.append(grid[ni][nj])
                stack.append((ni, nj, new_path))
    
    # 反转结果,让顺序和递归方案一致
    return valid_paths[::-1]

测试同样的网格,输出结果和递归方案完全一致。

进阶:类封装+缓存(适合高频复用)

如果需要频繁处理同一网格,用类来封装缓存会更方便,避免每次调用都重新计算:

from functools import lru_cache
from typing import List

class PathFinder:
    def __init__(self):
        # 用网格的元组形式作为缓存键(列表不可哈希,转成元组)
        self._cache = {}
    
    def find_paths(self, grid: List[List[int]]) -> List[List[int]]:
        grid_tuple = tuple(tuple(row) for row in grid)
        # 先查缓存,存在直接返回
        if grid_tuple in self._cache:
            return self._cache[grid_tuple]
        
        if not grid or not grid[0]:
            result = []
        else:
            rows, cols = len(grid), len(grid[0])
            end_i, end_j = rows - 1, cols - 1
            if grid[end_i][end_j] <= grid[0][0]:
                result = []
            else:
                @lru_cache(maxsize=None)
                def dfs(i, j):
                    if i == end_i and j == end_j:
                        return [[grid[i][j]]]
                    paths = []
                    for di, dj in [(-1,0), (1,0), (0,-1), (0,1)]:
                        ni, nj = i+di, j+dj
                        if 0<=ni<rows and 0<=nj<cols and grid[ni][nj]>grid[i][j]:
                            for sub_path in dfs(ni, nj):
                                paths.append([grid[i][j]] + sub_path)
                    return paths
                result = dfs(0, 0)
        
        # 存入缓存
        self._cache[grid_tuple] = result
        return result

使用方式

# 初始化一个路径查找器
finder = PathFinder()

# 第一次计算,存入缓存
grid1 = [[1,4,3], [5,6,7]]
print(finder.find_paths(grid1))

# 第二次直接读缓存,速度更快
print(finder.find_paths(grid1))

# 处理新网格
grid2 = [[2,3], [1,4]]
print(finder.find_paths(grid2))

注意事项

  • 如果终点无法从起点到达(比如被更小的单元格完全阻断),函数会返回空列表
  • 递归方案的深度受限于Python默认递归栈深度(默认1000),大网格优先选迭代方案
  • 因为路径严格递增,所以不用担心循环路径的问题

内容的提问来源于stack exchange,提问作者ageow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 20:02:30