采访:使用递归的二维矩阵中的最大路径和。路径的恢复

Posted

技术标签:

【中文标题】采访:使用递归的二维矩阵中的最大路径和。路径的恢复【英文标题】:Interview : Maximum path sum in a 2-D matrix using recursion. Recovery of the path 【发布时间】:2017-01-07 02:34:09 【问题描述】:

问题

给定一个由非负数填充的 m x n 网格,找到一条从左上角到右下角的路径,最大化沿其路径的所有数字的总和。

注意:您只能在任何时间点向下或向右移动。

接近

我刚刚用天真的递归处理了这个问题,我为此编写的代码如下所示。 我遇到的问题是我无法弄清楚如何恢复网格中的路径。我通过引用(路径)传入了一个向量,因此我可以恢复每个递归调用的路径。

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int getMaxPath(vector<vector<int> > Grid, int r, int c, vector<int> &path)

    if((r > Grid.size()-1) || (c > Grid[0].size()-1))
        return 0;

    if(r==Grid.size()-1 && c==Grid[0].size()-1)
        return Grid[r][c];
    

    int rs = getMaxPath(Grid, r, c+1, path);
    int ds = getMaxPath(Grid, r+1, c, path);


    return max(rs,ds)+Grid[r][c];



int maxPath(vector<vector<int> > Grid, vector<int> &path)

    return getMaxPath(Grid, 0, 0, path);


int main() 

    vector<vector<int> > mat5,0,8,12, 11,16,9,13,10,2,15,300,3,14,18,19;
    vector<int>path;

    path.push_back(mat[0][0]);
    int result = maxPath(mat, path);
    cout << result << endl;

    for(auto i : path)
        cout << i << " " << endl;

    return 0;

正如我们所看到的,代码的主要部分是递归,我会这样恢复路径(注释)--

int getMaxPath(vector<vector<int> > Grid, int r, int c, vector<int> &path)

    if((r > Grid.size()-1) || (c > Grid[0].size()-1))
        return 0;

    if(r==Grid.size()-1 && c==Grid[0].size()-1)
        return Grid[r][c];
    

    int rs = getMaxPath(Grid, r, c+1, path);
    int ds = getMaxPath(Grid, r+1, c, path);

    (rs > ds) ? path.push_back(Grid[r][c+1]) ? path.push_back(Grid[r+1][c]); // Recover path here. 
    return max(rs,ds)+Grid[r][c];


但我在某处遗漏了要点,因为这会导致当前元素的多个副本在从递归调用中展开和展开时进入路径。

我做错了什么?

【问题讨论】:

如果你在一次采访中给了我这个答案,我会问你这个函数需要多长时间,以及完成这项工作的函数应该需要多长时间。跨度> 有很多更好的方法来解决这个问题:你考虑过动态规划吗? @MattTimmermans 这个函数是时间指数的 (2^(r+c))...当然可以使用 DP [?] 将时间减少到 O(m*n) 但是这个想法是为了获得正确的逻辑来恢复路径。 没错。当您提出 O(n*m) 算法时,路径将更容易恢复。 其实不用恢复。只需确定正确的路径还是下行路径是更好的选择。根本不需要递归。 【参考方案1】:

由于图形被编码为矩阵,因此每个顶点应该是一对,即std::pair&lt;int, int&gt; 表示顶点的(row, column)

因此路径参数应声明为vector&lt;pair&lt;int, int&gt;&gt;&amp; path

int getMaxPath(vector<vector<int> > Grid, int r, int c, vector<pair<int, int>>& path)

    ...
    (rs > ds) ? path.emplace_back(r, c+1) : path.emplace_back(r+1, c);

编辑

该方法仍然不正确,因为每个递归调用,包括那些未选择(最佳)的调用,仍会将其结果放入路径中。我们需要将一个单独的向量传递给每个递归调用,并且只有在它被选中时才将其附加到我们的:

int getMaxPath(vector<vector<int> > Grid, int r, int c, vector<pair<int, int >> &path)

    if ((r > Grid.size() - 1) || (c > Grid[0].size() - 1))
        return 0;

    path.emplace_back(r, c);
    if (r == Grid.size() - 1 && c == Grid[0].size() - 1)
        return Grid[r][c];

    vector<pair<int, int >> rsPath, dsPath;
    int rs = getMaxPath(Grid, r, c + 1, rsPath);
    int ds = getMaxPath(Grid, r + 1, c, dsPath);

    if (rs > ds) 
        path.insert(path.end(), rsPath.begin(), rsPath.end());
        return rs + Grid[r][c];
    
    else 
        path.insert(path.end(), dsPath.begin(), dsPath.end());
        return ds + Grid[r][c];
    

p.s.:如果如您所说,您想捕获矩阵权重而不是坐标,您可以调整它,但遵循相同的逻辑以避免这些重复。

测试

int maxPath(vector<vector<int> > Grid, vector<pair<int, int>> &path)

    return getMaxPath(Grid, 0, 0, path);


int main()

        vector<vector<int> > mat  5,0,8,12 , 11,16,9,13 , 10,2,15,300 , 3,14,18,19  ;
        vector<pair<int, int>>path;

        int result = maxPath(mat, path);
        cout << result << endl;

    for (auto it = path.begin(); it != path.end(); it++)
        std::cout << "(" << it->first << ", " << it->second << ")";
    system("pause"); return 0;

输出

(0, 0)(1, 0)(1, 1)(1, 2)(2, 2)(2, 3)(3, 3)

【讨论】:

嗨,我的意思是恢复网格中的元素...例如理想情况下,上述网格会导致此路径 ==> 5,11,16,9,15,300,19。即使我尝试了你的方法,我的问题仍然存在。但不是重复的元素,我会得到重复的位置。我应该得到 (0,0, (1,0),(1,1),(1,2),(2,2),(2,3),(3,3) 但我得到 1 ,0 1,1 2,1 3,1 3,2 3,3 2,2 3,2 3,3 2,3 3,3 3,3 1,2 2,2 3,2 3,3 2,3 3,3 3,3 2,2 2,3 3,3 3,3 2,3 3,3 1,1 1,2 2,2 3,2 3,3 2,3 3,3 3,3 2, 2 2,3 3,3 .... 哦,我明白了!事实上,递归调用,包括那些没有被调用的调用,仍然会将它们的结果放在路径中。我认为只要我们将same vector by reference 传递给递归函数,情况就会如此。我们需要将一个单独的向量传递给每个向量,并且只有在它被选中时才将其附加到我们的向量中。我将编辑我的答案以提出解决方案 谢谢!这是非常详细的。我会追踪电话,看看你的电话有什么意义。谢谢您的帮助。真的很感激。

以上是关于采访:使用递归的二维矩阵中的最大路径和。路径的恢复的主要内容,如果未能解决你的问题,请参考以下文章

图论刷题-2剑指 Offer 12. 矩阵中的路径

图论刷题-2剑指 Offer 12. 矩阵中的路径

剑指 Offer 12. 矩阵中的路径 - 7月23日

剑指offer65:矩阵中的路径(二维数组,二分查找)

计算二维数组上的路径数(网格旅行者)

124. 二叉树中的最大路径和。 递归