网格图中递增路径的数目[dfs逆向路径+记忆dfs]

前言

DFS本质是一直暴力枚举法,往往存在很多的重复计算,从而导致时间复杂度飙升至指数级别。而用数组记录曾经计算过结果,防止重复计算从而减少时间的浪费,本质就是空间换时间,也称记忆化搜索。

一、网格图中递增路径的数目

在这里插入图片描述

二、记忆化搜索

package competition.single300;

public class CountPaths {
    // 上下左右都可以走,为了用循环代替坐标i/j的变换,所以采用提前定义好的偏差矩阵。
    static final int[][] gaps = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    // 为了方便取余时写的简单,且可统一修改取余对象,所以用一个变量指代,形成一级索引。
    static final int mod = (int) 1e9 + 7;
    // 为了方便取格子的长宽,所以提前用简单变量记录格子长宽。
    int m, n;

    public int countPaths(int[][] grid) {
        // 初始化格子长宽。
        m = grid.length;
        n = grid[0].length;
        // 用数组记住从第(i,j)出发的路径个数,不用每次都dfs到最深处。
        int[][] f = new int[m][n];
        int ans = 0;
        // 以每个节点作为起点,找到可连通的节点数,以该节点为起点,为一个路径,每多加一个节点,为一个新路径,所以节点数就是路径可能数。
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                ans += dfs(grid, 1 << 31, i, j, f);
                ans %= mod;
            }
        }
        return ans;
    }

    private int dfs(int[][] grid, int pre, int i, int j, int[][] f) {
        // 递归结束处,无格子就是0,回溯每多一个格子就+1,表示一条新路径。
        if (i < 0 || j < 0 || i == m || j == n || pre >= grid[i][j]) return 0;
        // 如果以该格子为起点,已经知道递增路径的个数了,就直接返回,不用再dfs进行计算了。(空间换时间)
        if (f[i][j] != 0) return f[i][j];
        // 没有路过 过 这个节点,就没有回溯给其赋值。
        f[i][j] = 1;
        // dfs寻找路径数。
        for (int[] gap : gaps) {
            int ni = i + gap[0], nj = j + gap[1];
            // 每条分路径过来,加上当前格子,都是一个新路径。
            f[i][j] += dfs(grid, grid[i][j], ni, nj, f);
            // 防止累计过多而溢出
            f[i][j] %= mod;
        }
        return f[i][j];
    }
}

总结

1)空间换时间,DFS典型的优化方式之一,记忆化。当然DFS还有剪枝+减少根深度+减少根个数等等优化方式。

参考文献

[1] LeetCode 网格图中递增路径的数目

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值