矩阵中的最长递增路径

文章目录

  • 矩阵中的最长递增路径
    • 一、问题描述
    • **方法一:朴素的深度优先搜索 【超时】**
    • **方法二:记忆化深度优先搜索 【通过】**
    • **方法三:动态规划**
    • **方法四:广度优先搜索**

一、问题描述

给定一个整数矩阵,找出最长递增路径的长度。对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上
移动或移动到边界外(即不允许环绕)。

示例 1:

输入: nums =
[[9,9,4],[6,6,8],[2,1,1]
]
输出: 4
解释: 最长递增路径为 [1, 2, 6, 9]。

示例 2:

输入: nums =
[[3,4,5],[3,2,6],[2,2,1]
]
输出: 4
解释: 最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。

方法一:朴素的深度优先搜索 【超时】

直觉

  • 深度优先搜索可以找到从任何单元格开始的最长递增路径。我们可以对全部单元格进行深度优先搜索。

算法

  • 每个单元格可以看作图 GG 中的一个定点。若两相邻细胞的值满足 a < b,则存在有向边 (a, b)。问题转化成:
  • 寻找有向图 GG 中的最长路径。
  • 显然,我们可以使用深度优先搜索或广度优先搜索从根开始访问连接的所有细胞。在搜索期间更新路径的最大长度,并在搜索完成后得到答案。
  • 一般而言,在深度优先搜索或广度优先搜索中,我们可以使用集合visited 来避免重复访问。在下一节中我们将介绍基于此的更优算法。
class Solution {public:vector<vector<int>> dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};int m, n;int dfs(vector<vector<int>>& matrix, int i, int j) {int ans = 0;for ( auto d : dirs) {int x = i + d[0], y = j + d[1];if (0 <= x && x < m && 0 <= y && y < n && matrix[x][y] > matrix[i][j])ans = max(ans, dfs(matrix, x, y));}return ++ans;}int longestIncreasingPath(vector<vector<int>>& matrix) {if (matrix.size() == 0) return 0;m = matrix.size();n = matrix[0].size();int ans = 0;for (int i = 0; i < m; ++i)for (int j = 0; j < n; ++j)ans = max(ans, dfs(matrix, i, j));return ans;}
};

方法二:记忆化深度优先搜索 【通过】

直觉

  • 将递归的结果存储下来,这样每个子问题只需要计算一次。

算法

  • 从上面的分析中,我们知道在淳朴的深度优先搜索方法中有许多重复的计算。

  • 一个优化途径是我们可以用一个集合来避免一次深度优先搜索中的重复访问。该优化可以将一次深度优先搜索的时间复杂度优化到 O(mn),总时间复杂度 O(m2 n2)

  • 下面介绍一个更有力的优化方法,记忆化

  • 在计算中,记忆化是一种优化技术,它通过存储“昂贵”的函数调用的结果,在相同的输入再次出现时返回缓存的结果,以此加快程序的速度。

  • 在本问题中,我们多次递归调用 dfs(x, y) 。但是,如果我们已经知道四个相邻单元格的结果,就只需要常数时间。在搜索过程中,如果未计算过单元格的结果,我们会计算并将其缓存;否则,直接从缓存中获取之.

class Solution {public:int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};vector<vector<int> > memo;int dfs(vector<vector<int> >& matrix, int r, int c, int R, int C){if (memo[r][c] != 0) {return memo[r][c];}int t = 0;for (int i = 0; i < 4; ++i){int nr = r + dirs[i][0];int nc = c + dirs[i][1];if (nr >= 0 && nr < R && nc >= 0 && nc < C && matrix[nr][nc] > matrix[r][c]) {t = max(t, dfs(matrix, nr, nc, R, C));}}memo[r][c] = 1 + t;return memo[r][c];}int longestIncreasingPath(vector<vector<int>>& matrix) {if (matrix.empty() || matrix[0].empty()) return 0;int R = matrix.size();int C = matrix[0].size();memo = vector<vector<int> >(R, vector<int>(C, 0));int res = 0;for (int i = 0; i < R; ++i){for (int j = 0; j < C; ++j) {res = max(res, dfs(matrix, i, j, R, C));}}return res;}
};

方法三:动态规划

class Point {public:int x, y, v;Point(int ix, int iy, int iv) {x = ix;y = iy;v = iv;}
};class Solution {public:int longestIncreasingPath(vector<vector<int>>& matrix) {if (matrix.size() == 0)return 0;const int rows = matrix.size();const int cols = matrix[0].size();vector<vector<int>> dp(rows, vector<int>(cols, 1));vector<Point> vp;vp.reserve(rows * cols);for (int i = 0; i < rows; i++)for (int j = 0; j < cols; j++) {vp.push_back(Point(i, j, matrix[i][j]));}// 对坐标排序sort(vp.begin(), vp.end(), [](const Point &lhs, const Point &rhs){return lhs.v < rhs.v;});int ret = 1;for (const auto &p : vp) {auto x = p.x;auto y = p.y;auto v = p.v;// 寻找附近比当前矮的点的最高DP值if (x > 0 && matrix[x - 1][y] < v && dp[x - 1][y] + 1 > dp[x][y])dp[x][y] = dp[x - 1][y] + 1;if (x < rows - 1 && matrix[x + 1][y] < v && dp[x + 1][y] + 1 > dp[x][y])dp[x][y] = dp[x + 1][y] + 1;if (y > 0 && matrix[x][y - 1] < v && dp[x][y - 1] + 1 > dp[x][y])dp[x][y] = dp[x][y - 1] + 1;if (y < cols - 1 && matrix[x][y + 1] < v && dp[x][y + 1] + 1 > dp[x][y])dp[x][y] = dp[x][y + 1] + 1;if (dp[x][y] > ret)ret = dp[x][y];}return ret;}
};

方法四:广度优先搜索

  • 广度优先则不能完整的构造偏序关系。能做的是当位置(i,j)的路径长度被增加后,那么其上下左右的位置,潜在的路径长度都可能被修改。

  • 这些潜在的要修改的位置,可以存入队列。通过队列然后逐层更新路径长度。

算法的计算过程:

  • 先访问位置(0,0),值为9. 其长度为1. 其周围,没有要更新的位置。
  • 位置(0,1),值为9, 其长度为1. 其周围,没有要更新的位置。
  • 位置(0,2)值为4, 其长度为1。但是周围有位置(0,1)和位置(1,2)需要更新长度为2。但是 位置(0,1)和位置(1,2) 周围没有需要更新的位置。
  • 位置(1,0)值为6,长度为1。 周围有位置(0,0)需要更新长度为2。
  • 位置 (1,1)值为6,长度为1。 周围有 位置(0,1)和位置(1,2) 需要更新长度为2。
  • 位置(1,2)值为8,长度为2。 周围没有需要更新的位置。
  • 位置(2,0)值为2,长度为1。 周围有位置(1,0) 需要更新长度为2。 位置(1,0) 周围
  • 位置(0,0)需要更新长度为3.
  • 位置(2,1)值为1,长度为1。 周围有位置(2,0)和(1,1) 需要更新长度为2。 位置(1,0) ,(0,1),(1,2)需要更新长度为3. 位置(0,0)更新长度为4.
  • 逐层更新位置路径的最大长度。

用广度优先搜索,用队列,完成上述逐层更新的功能

    int R,C; int longestIncreasingPath(vector<vector<int>>& matrix) {if(!(R=matrix.size()) || !(C=matrix[0].size())){return 0;}int ans = 0;vector<vector<int>> vis(R,vector<int>(C,0));for(int i=0;i<R;++i){for(int j=0;j<C;++j){if(!vis[i][j]){ans = max(ans,bfs(matrix,vis,i,j));}}}return ans;}int bfs(const vector<vector<int>>& grid,vector<vector<int>>& vis,int x,int y){vis[x][y] = 1;int max_h = 0;const static int dx[4]={1,-1,0,0};const static int dy[4]={0,0,1,-1};        typedef pair<int,int> Pair;queue<Pair> Q;Q.push(make_pair(x,y));while(Q.size()){Pair p = Q.front();Q.pop();const int & _x = p.first;const int & _y = p.second;max_h = max(max_h,vis[_x][_y]);for(int i=0;i<4;++i){const int nx = _x + dx[i];const int ny = _y + dy[i];if(in_grid(nx,ny) && grid[nx][ny] > grid[_x][_y]){if(vis[_x][_y] + 1 > vis[nx][ny]){vis[nx][ny] = vis[_x][_y] + 1;Q.push(make_pair(nx,ny));}}} }return max_h;}bool in_grid(int x,int y){return x>=0 && x < R && y>=0 && y<C;}

矩阵中的最长递增路径相关推荐

  1. 329. Longest Increasing Path in a Matrix 矩阵中的最长递增路径

    给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕). 示例 1: 输入: nums = [[9,9 ...

  2. java某个起点出发的最长路径_【leetcode-动态规划】矩阵中的最长递增路径

    [leetcode-动态规划]矩阵中的最长递增路径 题目: 给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即 ...

  3. 329. 矩阵中的最长递增路径

    2020-06-09 1.题目描述 矩阵中的最长递增路径 2.题解 在这里我们可以将其视作有向图,如果当前的数比其四周位置上的数要小的话,就构建一条从当前数指向其 周围的边,要求得最长的递增路径,那么 ...

  4. Leetcode--329. 矩阵中的最长递增路径

    给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕). 示例 1: 输入: nums =  [   ...

  5. 329 矩阵中的最长递增路径

    题目描述: 给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕). 示例 1: 输入: nums = ...

  6. 算法-------矩阵中的最长递增路径(Java版本)

    题目 给定一个整数矩阵,找出最长递增路径的长度.对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕).示例 1:输入: nums = [[9,9 ...

  7. leetcode329. 矩阵中的最长递增路径(dfs)

    给定一个整数矩阵,找出最长递增路径的长度.对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕).示例 1:输入: nums = [[9,9,4] ...

  8. leetcode329. 矩阵中的最长递增路径

    给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向上移动或移动到边界外(即不允许环绕). 示例 1: 输入: nums =  [   ...

  9. LeetCode 329. 矩阵中的最长递增路径(记忆化递归)

    文章目录 1. 题目 2. 解题 2.1 记忆化递归 2.2 拓扑排序 1. 题目 给定一个整数矩阵,找出最长递增路径的长度. 对于每个单元格,你可以往上,下,左,右四个方向移动. 你不能在对角线方向 ...

最新文章

  1. js禁止用户右键等操作
  2. angular 应为声明或语句_“允许”员工自愿降薪后,多益网络再发声:声明降薪非自愿者奖 3 万...
  3. SAP web 开发 (第二篇 bsp 开发 mvc模式 Part2 )
  4. 信息学奥赛一本通(2020:【例4.5】第几项)
  5. 【安全】This base cannot be created with PLA.
  6. linux 新建文件夹命令
  7. 微信小程序记录v1.0
  8. LambdaQueryWrapper的不同写法
  9. 计算机主板cpu插座分类,Intel历代CPU插槽类型、架构、常用主板大全
  10. 【TensorFlow】tf.expand_dims()函数
  11. 计算机用word做贺卡,利用word制作贺卡
  12. 3、需求调研 - 产品管理系列文章
  13. UNCTF2022中RSA题目总结
  14. NoneType‘ object has no attribute ‘loader‘
  15. 高精度乘法(正负数皆可(Bull Math)POJ)
  16. 非制冷式红外探测器原理研究(课题总结论文)
  17. GPS接收机的灵敏度分析
  18. html5网页播放声音
  19. K-均值聚类算法(含MATLAB程序)
  20. 进腾讯了,38k....

热门文章

  1. 201103阶段二linux gdb调试与ftp配置
  2. CSVN部署安装,实现web管理svn
  3. 基于DDD的.NET开发框架 - ABP模块设计
  4. JavaScript高级程序设计(第三版)学习笔记1~5章
  5. Dynamics CRM 2013 初体验(1):系统的安装
  6. 邮件系统三功能 建金字塔防护体系
  7. REVIT模型之机器人瓦力
  8. 域名到期续费删除的相关规则
  9. HDU - 7091 重叠的子串(后缀自动机+set启发式合并+树上倍增)
  10. HDU多校4 - 6813 Last Problem(构造)