leetcode-6110:网格图中递增路径的数目

简介: leetcode-6110:网格图中递增路径的数目

题目

题目连接

给你一个 m x n 的整数网格图 grid ,你可以从一个格子移动到 4 个方向相邻的任意一个格子。

请你返回在网格图中从 任意 格子出发,达到 任意 格子,且路径中的数字是 严格递增 的路径数目。由于答案可能会很大,请将结果对 1 0 9 + 7 10^9 + 7109+7 取余 后返回。

如果两条路径中访问过的格子不是完全相同的,那么它们视为两条不同的路径。

示例 1:

输入:grid = [[1,1],[3,4]]
输出:8
解释:严格递增路径包括:
- 长度为 1 的路径:[1],[1],[3],[4] 。
- 长度为 2 的路径:[1 -> 3],[1 -> 4],[3 -> 4] 。
- 长度为 3 的路径:[1 -> 3 -> 4] 。
路径数目为 4 + 3 + 1 = 8 。

示例 2:

输入:grid = [[1],[2]]
输出:3
解释:严格递增路径包括:
- 长度为 1 的路径:[1],[2] 。
- 长度为 2 的路径:[1 -> 2] 。
路径数目为 2 + 1 = 3 。

解题

方法一:dfs记忆化搜索

通过memory数组保存,每个格点的递增路径数目

比如memory[i][j],表示终点为(i,j)的递增路径数目

class Solution {
public:
    const int MOD=1e9+7;
    vector<vector<int>> dirs={{-1,0},{0,-1},{1,0},{0,1}};
    vector<vector<int>> memory;
    int dfs(vector<vector<int>>& grid,int i,int j){
        if(memory[i][j]>0) return memory[i][j];
        memory[i][j]=1;
        for(vector<int>& dir:dirs){
            int nx=i+dir[0];
            int ny=j+dir[1];
            if(nx<0||nx>=grid.size()||ny<0||ny>=grid[0].size()||grid[i][j]<=grid[nx][ny]) continue;
            memory[i][j]=(memory[i][j]+dfs(grid,nx,ny))%MOD;
        }
        return memory[i][j];
     }
    int countPaths(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        memory.resize(m,vector<int>(n));
        int res=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                res=(res+dfs(grid,i,j))%MOD;
            }
        }
        return res;
    }
};

方法二:动态规划(超时)

dp[i][j][l]表示格点为(i,j),路径长度为l的数量,

这样做的目的是因为,只有得到长度为 l-1的路径数量,才能计算出长度为l的路径数量。

缺点:

然而比如 grid[2][3]>grid[2][4]

但是每次都会进行重复比较,遍历到(2,3),会跟右边比,遍历到(2,4)还要跟左边比,并且没法记忆化,因为dp[i][j][l]只是l长度的结果,只是一个中间值,不是最终结果。

而方法一:是直接保存了每个格点的所有递增路径数目,因此可以记忆化。(dfs,复杂度O ( n 2 ) O(n^2)O(n2)

方法二可以得到每种路径长度的数量,小量数据可以通过,但是会超时。(矩阵遍历,复杂度O ( n 3 ) O(n^3)O(n3)

class Solution {
public:
    const int Mod=1e9+7;
    vector<vector<int>> dirs={{-1,0},{0,-1},{1,0},{0,1}};
    int countPaths(vector<vector<int>>& grid) {
        int res=0;
        int m=grid.size();
        int n=grid[0].size();
        int maxPath=m*n;
        vector<vector<vector<int>>> dp(m,vector<vector<int>>(n,vector<int>(m*n+1)));
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                dp[i][j][0]=0;
                dp[i][j][1]=1;
                res++;
            }
        }
        for(int l=2;l<=maxPath;l++){
            for(int i=0;i<m;i++){
                for(int j=0;j<n;j++){
                    dp[i][j][l]=0;
                    for(vector<int>& dir:dirs){
                        int nx=i+dir[0];
                        int ny=j+dir[1];
                        if(nx>=0&&nx<m&&ny>=0&&ny<n&&grid[i][j]>grid[nx][ny]){
                            dp[i][j][l]+=dp[nx][ny][l-1];
                        }
                    }
                    res=(res+dp[i][j][l])%Mod;
                }
            }
        }
        return res;
    }
};
相关文章
【LeetCode 35】112.路径总和
【LeetCode 35】112.路径总和
121 0
|
6月前
|
Go 开发者 索引
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣33 / 81/ 153/154)(Go语言版)
本文深入探讨了LeetCode中四道关于「搜索旋转排序数组」的经典题目,涵盖了无重复和有重复元素的情况。通过二分查找的变形应用,文章详细解析了每道题的解题思路和Go语言实现代码。关键点包括判断有序区间、处理重复元素以及如何缩小搜索范围。文章还总结了各题的异同,并推荐了类似题目,帮助读者全面掌握二分查找在旋转数组中的应用。无论是初学者还是有经验的开发者,都能从中获得实用的解题技巧和代码实现方法。
303 14
|
5月前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
237 1
|
7月前
|
算法 Go
【LeetCode 热题100】深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)(Go语言版)
本博客深入探讨二叉树的深度计算、结构变换与路径分析,涵盖四道经典题目:104(最大深度)、226(翻转二叉树)、114(展开为链表)和543(二叉树直径)。通过递归与遍历策略(前序、后序等),解析每题的核心思路与实现方法。结合代码示例(Go语言),帮助读者掌握二叉树相关算法的精髓。下一讲将聚焦二叉树构造问题,欢迎持续关注!
188 10
|
7月前
|
Go
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣437 / 236 )(Go语言版)
本文深入探讨二叉树中路径与祖先问题,涵盖两道经典题目:LeetCode 437(路径总和 III)和236(最近公共祖先)。对于路径总和 III,文章分析了双递归暴力解法与前缀和优化方法,后者通过哈希表记录路径和,将时间复杂度从O(n²)降至O(n)。在最近公共祖先问题中,采用后序遍历递归查找,利用“自底向上”的思路确定最近公共祖先节点。文中详细解析代码实现与核心要点,帮助读者掌握深度追踪技巧,理解树结构中路径与节点关系的本质。这类问题在面试中高频出现,掌握其解法意义重大。
172 4
【LeetCode 36】113.路径总和II
【LeetCode 36】113.路径总和II
114 0
【LeetCode 34】257.二叉树的所有路径
【LeetCode 34】257.二叉树的所有路径
106 0
|
存储 算法 Linux
LeetCode第71题简化路径
文章讲述了LeetCode第71题"简化路径"的解题方法,利用栈的数据结构特性来处理路径中的"."和"..",实现路径的简化。
LeetCode第71题简化路径
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
247 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
354 2

热门文章

最新文章