具有循环依赖性的DFS

时间:2017-10-10 06:03:17

标签: algorithm matrix depth-first-search breadth-first-search

我试图解决this challenge

  

给出表示高度的m×n矩阵的非负整数   一个大陆的每个单元格,太平洋"接触左边   矩阵的顶部边缘和大西洋"触及右边   和底边。

     

水只能从四个方向(向上,向下,向左或向右)流动   一个单元格到另一个高度相等或更低的单元格。

     

找到水可以流到两者的网格坐标列表   太平洋和大西洋。

     

注意:返回的网格坐标的顺序无关紧要。两者都是   和n小于150.

     

示例:

rmiregistry

这是我的解决方案

 Given the following 5x5 matrix:

   Pacific ~   ~   ~   ~   ~ 
        ~  1   2   2   3  (5) *
        ~  3   2   3  (4) (4) *
        ~  2   4  (5)  3   1  *
        ~ (6) (7)  1   4   5  *
        ~ (5)  1   1   2   4  *
           *   *   *   *   * Atlantic

 Return:

 [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions
 with parentheses in above matrix).

但我的解决方案输入失败

class Solution {
public:
    vector<pair<int, int>> result;
    map<pair<int, int>, pair<bool, bool>> dp;
    //    P     A
    pair<bool, bool> doPacific(vector<vector<int>>& matrix, vector<vector<bool>> & visited,  int row, int col)
    {
        cout << row << ' ' << col << endl;
        if(col < 0 || row < 0)
        {
            return pair<bool, bool>(true, false);
        }
        if(col >= matrix[0].size() || row >= matrix.size())
        {
            return pair<bool, bool>(false, true);
        }
        if(visited[row][col])
        {
            return dp[make_pair(row, col)];
        }
        pair<bool,bool> left(false, false);
        pair<bool,bool> right(false, false);
        pair<bool,bool> top(false, false);
        pair<bool,bool> bottom(false, false);
        visited[row][col] = true;
    // Go Down if index is invalid or has valid index and water level
    if(((row + 1 < matrix.size()) && (matrix[row + 1][col] <= matrix[row][col])) || row + 1 >= matrix.size())
    {
        bottom = doPacific(matrix,visited, row + 1, col);
    }
    if(((row - 1 >= 0) && (matrix[row - 1][col] <= matrix[row][col])) || (row -1 < 0))
    {
            top = doPacific(matrix,visited, row - 1, col);
    }
    if(((col + 1 < matrix[0].size()) && (matrix[row][col + 1] <= matrix[row][col])) || (col + 1>= matrix[0].size()))    
    {
            right = doPacific(matrix,visited, row, col + 1);
    }
    if(((col - 1 >=0) && (matrix[row][col - 1] <= matrix[row][col])) || (col -1 < 0))
    {
        left = doPacific(matrix,visited, row, col - 1);
    }

        pair<bool, bool>returnValue(false, false);

        returnValue.first |= left.first;
        returnValue.second |= left.second;

        returnValue.first |= right.first;
        returnValue.second |= right.second;

        returnValue.first |= bottom.first;
        returnValue.second |= bottom.second;

        returnValue.first |= top.first;
        returnValue.second |= top.second;

        dp.insert(make_pair(make_pair(row, col), returnValue));
        if(returnValue.first && returnValue.second)
        {
            result.push_back(make_pair(row, col));
        }
        return returnValue;

    }
    vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
        vector<vector<bool>> visited(matrix.size(), vector<bool>(matrix[0].size(), false));
        result.clear();
        dp.clear();
        for(int i=0; i< matrix.size(); ++i)
        {
            for(int j=0; j < matrix[0].size(); ++j)
            {
                if(!visited[i][j])
                {
                    doPacific(matrix, visited, i, j); 
                }                
            }
        }
        return result;
    }
};

我的回答只省略了索引[10,10,10] [10, 1,10] [10,10,10]

当我跟踪递归树时,它看起来像这样。

(0,1)

我的问题是当现有节点和要添加的节点之间存在循环依赖时,如何解决这种情况。

解决此类问题的方法是否正确。

1 个答案:

答案 0 :(得分:2)

您的实施中存在多个问题:

  1. 您只考虑节点的两种状态:not visitedvisited。但你确实可以陷入第三种状态。通常我们会考虑颜色whitegrayblack。在您的代码中,grayblack颜色在单个visited状态下合并在一起。
  2. 进入新节点时,如果您将节点标记为visited,则不会再次访问该节点,只需在dp数组中查找其值即可。正如您自己发现的那样,它不起作用,因为dp数组仅适用于black单元格,而不适用于gray单元格。但由于问题1.你无法有所作为
  3. dp单元格未正确更新gray数组的原因是您尝试同时执行两项操作:

    1. 计算太平洋是否触及某个单元格
    2. 计算大西洋是否触及某个单元格
    3. 但是使用单个DFS,您可以在前向路径上更新一个属性,而第二个属性仅在遍历的后向路径上更新。

      解决方案是使用两个DFS分别更新每个属性。

      您可以尝试从一个海洋开始,而不是一个DFS,而不是单个DFS。每个泛洪填充都是DFS,但来自不同的源,并且提升了不同的visited属性。显然,你改变了流量的条件,即你的 water 从低海拔高度流向高海拔。

      在两次洪水填充之后,您最终输出两个海洋触及的所有细胞。泛洪填充为O(n*m),因此与当前实施相比,它不会降低复杂性。

      在我的实施中,我为每个海洋开始n+m洪水填充,但我保留了相同的visiteds地图,因此它仍保留在O(n*m)

      这是一个示例解决方案(可读但仍然比91%的c ++提交速度快)。看到我使用位掩码技术来标记海洋访问的单元格(1 - &gt;太平洋,2 - >大西洋,3 - >两者)而不是pair<bool,bool>,但这仅用于性能优化。 / p>

      int width, height;
      vector<vector<unsigned char>> visiteds;
      
      void floodFill(int i, int j, unsigned char mask, vector<vector<int>>& matrix) {
          visiteds[i][j] = visiteds[i][j] | mask;
      
          auto& h = matrix[i][j];
      
          if(i > 0 && matrix[i-1][j] >= h && !(visiteds[i-1][j] & mask))
              floodFill(i-1, j, mask, matrix);
      
          if(i < height-1 && matrix[i+1][j] >= h && !(visiteds[i+1][j] & mask))
              floodFill(i+1, j, mask, matrix);
      
          if(j > 0 && matrix[i][j-1] >= h && !(visiteds[i][j-1] & mask))
              floodFill(i, j-1, mask, matrix);
      
          if(j < width-1 && matrix[i][j+1] >= h && !(visiteds[i][j+1] & mask))
              floodFill(i, j+1, mask, matrix);
      }
      
      vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
          vector<pair<int,int>> cells;
          height = matrix.size();
          if(! height)
              return cells;
      
          width = matrix[0].size();
          visiteds.clear();
          visiteds.resize(height, vector<unsigned char>(width, 0));
      
          for(int k=0; k<height; ++k) {
              floodFill(k, 0, 1, matrix);
              floodFill(k, width-1, 2, matrix);
          }
          for(int k=0; k<width; ++k) {
              floodFill(0, k, 1, matrix);
              floodFill(height-1, k, 2, matrix);
          }
      
          for(size_t i=0; i<height; ++i)
              for(size_t j=0; j<width; ++j)
                  if(visiteds[i][j] == 3)
                      cells.push_back(make_pair(i, j));
          return cells;
      }