0
点赞
收藏
分享

微信扫一扫

[典型]BM61 矩阵最长递增路径-较难

​​BM61 矩阵最长递增路径​​

知识点​​dfs​​​​动态规划​​​​图​​

描述

给定一个 n 行 m 列矩阵 matrix ,矩阵内所有数均为非负整数。 你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。并输出这条最长路径的长度。这个路径必须满足以下条件:


1. 对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外。

2. 你不能走重复的单元格。即每个格子最多只能走一次。


数据范围:[典型]BM61 矩阵最长递增路径-较难_搜索[典型]BM61 矩阵最长递增路径-较难_记忆化搜索_02进阶:空间复杂度 [典型]BM61 矩阵最长递增路径-较难_记忆化搜索_03 ,时间复杂度 [典型]BM61 矩阵最长递增路径-较难_记忆化搜索_03

例如:当输入为[[1,2,3],[4,5,6],[7,8,9]]时,对应的输出为5,其中的一条最长递增路径如下图所示:[典型]BM61 矩阵最长递增路径-较难_数组_05

示例1

输入:

[[1,2,3],[4,5,6],[7,8,9]]

复制返回值:

5

复制说明:

1->2->3->6->9即可。当然这种递增路径不是唯一的。

示例2

输入:

[[1,2],[4,3]]

复制返回值:

4

复制说明:

1->2->3->4

题解

方法一:暴力dfs+辅助数组

思路:

  1. 使用一个辅助数组v[i][k]来表示遍历过程中是否已经访问过,0表示没有访问过,1表示访问过
  2. 遍历整个矩阵,选取任意的mat[i][k]为七点,往四个方向递归访问
  3. 返回最大长度

注意:

这个解法时间超了~~

代码如下:

#include <bits/stdc++.h>

using namespace std;

// https://www.nowcoder.com/practice/7a71a88cdf294ce6bdf54c899be967a2?tpId=295&tqId=1076860&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295
// BM61 矩阵最长递增路径

int find_path(vector<vector<int>> &matrix, int i, int k, std::vector<std::vector<int>> &v)
{
int len = 1;
v[i][k] = 1; // 表示i,k位置已经被访问
int value = matrix[i][k];
if (i > 0 && matrix[i - 1][k] > value && v[i - 1][k] == 0)
{
v[i - 1][k] = 1;
len = std::max(len, 1 + find_path(matrix, i - 1, k, v));
v[i - 1][k] = 0;
}
if (i < matrix.size() - 1 && matrix[i + 1][k] > value && v[i + 1][k] == 0)
{
v[i + 1][k] = 1;
len = std::max(len, 1 + find_path(matrix, i + 1, k, v));
v[i + 1][k] = 0;
}
if (k > 0 && matrix[i][k - 1] > value && v[i][k - 1] == 0)
{
v[i][k - 1] = 1;
len = std::max(len, 1 + find_path(matrix, i, k - 1, v));
v[i][k - 1] = 0;
}
if (k < matrix[0].size() - 1 && matrix[i][k + 1] > value && v[i][k + 1] == 0)
{
v[i][k + 1] = 1;
len = std::max(len, 1 + find_path(matrix, i, k + 1, v));
v[i][k + 1] = 0;
}
return len;
}

int solve(vector<vector<int>> &matrix)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return 0;
}

int max_length = 0;
for (int i = 0; i < matrix.size(); ++i)
{
for (int k = 0; k < matrix[0].size(); ++k)
{
std::vector<std::vector<int>> v(matrix.size(), std::vector<int>(matrix[0].size(), 0));
max_length = std::max(find_path(matrix, i, k, v), max_length);
}
}
return max_length;
}

解法二:暴力dfs的优化

由于使用了辅助数组,每次遍历的时候都需要分配内存,消耗比较大。可不可以省略掉这个辅助数组呢?答案是可以的。辅助数组只不过是在访问了mat[i][k]位置后将其标记,防止以后再访问。但是由于矩阵中的元素是有大小关系的,对于i、k任意相邻的一个位置,它的值要么大于它,要么小于等于它,即使重复计算也由于有大小关系的存在不会导致重复递归。只需要在进入下次递归前,将当前访问的值传入下次递归即可。

我们直接暴力枚举每个起点进行DFS,在过程中维护最大值即可。递归直接往四个方向进行即可,但是首先需要先判断四个方向的位置是否是可行的,也就是是否会出现越界的情况。

[典型]BM61 矩阵最长递增路径-较难_搜索_06

代码如下:

int dfs(vector<vector<int>> &matrix, int i, int k, int pre_value)
{
int value = matrix[i][k];
if (value <= pre_value) // 当前要访问的值,小于前面的节点,表示当前路径长度为0
{
return 0;
}

int len = 0;
if (i > 0)
{
len = std::max(len, dfs(matrix, i - 1, k, value));
}

if (i < matrix.size() - 1)
{
len = std::max(len, dfs(matrix, i + 1, k, value));
}

if (k > 0)
{
len = std::max(len, dfs(matrix, i, k - 1, value));
}

if (k < matrix[0].size() - 1)
{
len = std::max(len, dfs(matrix, i, k + 1, value));
}

return len + 1;
}

int solve(vector<vector<int>> &matrix)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return 0;
}

int max_length = 0;
for (int i = 0; i < matrix.size(); ++i)
{
for (int k = 0; k < matrix[0].size(); ++k)
{
max_length = std::max(dfs(matrix, i, k, -1), max_length);
}
}
return max_length;
}


解法三:dfs+记忆话搜索

解法一中,我们使用了一个辅助数组来记录路径是否已经被访问过,使用的是0和1来表示的。这导致每次搜索的时候本来已经搜索过的路径要重复的计算。如果我们使用这个辅助数组将已经计算过的结果保存起来,可以减少大量的计算。逻辑还是和解法一一样,只是将辅助数组的功能改变了。当辅助数组的值不为-1时表示已经搜索过这个路径,直接返回即可。

代码如下:

int memory_search(vector<vector<int>> &matrix, int i, int k, std::vector<std::vector<int>> &v)
{
if (v[i][k] != -1)
{
return v[i][k];
}

int len = 1;
int value = matrix[i][k];
if (i > 0 && matrix[i - 1][k] > value)
{
len = std::max(len, 1 + memory_search(matrix, i - 1, k, v));
}
if (i < matrix.size() - 1 && matrix[i + 1][k] > value)
{
len = std::max(len, 1 + memory_search(matrix, i + 1, k, v));
}
if (k > 0 && matrix[i][k - 1] > value)
{
len = std::max(len, 1 + memory_search(matrix, i, k - 1, v));
}
if (k < matrix[0].size() - 1 && matrix[i][k + 1] > value)
{
len = std::max(len, 1 + memory_search(matrix, i, k + 1, v));
}

v[i][k] = len;
return len;
}

int solve(vector<vector<int>> &matrix)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return 0;
}

int max_length = 0;
std::vector<std::vector<int>> v(matrix.size(), std::vector<int>(matrix[0].size(), -1));
for (int i = 0; i < matrix.size(); ++i)
{
for (int k = 0; k < matrix[0].size(); ++k)
{
max_length = std::max(memory_search(matrix, i, k, v), max_length);
}
}
return max_length;
}


举报

相关推荐

0 条评论