Leetcode

时间:2018-06-17 23:17:52

标签: algorithm big-o depth-first-search breadth-first-search

Here是问题描述。前两个建议的解决方案涉及DFS and BFS。这个问题涉及前两种方法:DFS和BFS。

我在此处列出了问题陈述,以便于阅读。

Given a 2d grid map of '1's (land) and '0's (water), count the number of 
islands. An island is surrounded by water and is formed by connecting adjacent
lands horizontally or vertically. You may assume all four edges of the grid are 
all surrounded by water.

    Example 1:

    Input:
    11110
    11010
    11000
    00000

    Output: 1


    Example 2:

    Input:
    11000
    11000
    00100
    00011

    Output: 3

我不清楚为什么DFS和BFS的时间复杂度都是O(rows * columns)。我看到这是如何在网格刚满0的情况下 - 我们只需要检查每个单元格。但是,DFS方法不会为搜索增加更多时间吗?即使我们通过在dfs方法中将它们更改为0来标记我们访问的单元格,我们仍然会因为两个外部循环而重新访问所有单元格。如果在具有大行和列数的大网格的情况下dfs可能具有O(n)的时间复杂度,那么时间复杂度是不是O(行*列* max [rows,cols])?此外,BFS方法与O(rows * cols * possibleMaxSizeOfQueue) possibleMaxSizeOfQueue再次为max[rows, cols]的情况不同?

for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          ++num_islands;
          dfs(grid, r, c);
        }
      }
    }

DFS的空间复杂度O(rows*cols)如何?当递归分支返回时,将调用堆栈空间视为已释放是不可能/通用的吗? BFS O(min(rows, cols))的空间复杂程度如何?我看到它的方式,在网格只有1的情况下,队列可以充满所有元素,从而为BFS空间复杂性提供O(rows*cols)

DFS解决方案

class Solution {
  void dfs(char[][] grid, int r, int c) {
    int nr = grid.length;
    int nc = grid[0].length;

    if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
      return;
    }

    grid[r][c] = '0';
    dfs(grid, r - 1, c);
    dfs(grid, r + 1, c);
    dfs(grid, r, c - 1);
    dfs(grid, r, c + 1);
  }

  public int numIslands(char[][] grid) {
    if (grid == null || grid.length == 0) {
      return 0;
    }

    int nr = grid.length;
    int nc = grid[0].length;
    int num_islands = 0;
    for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          ++num_islands;
          dfs(grid, r, c);
        }
      }
    }

    return num_islands;
  }
}
  

时间复杂度:O(M×N)其中M是行数   和N是列数。

     

空间复杂度:最坏情况O(M×N),如果是   网格地图充满了DFS超过M×N深的土地。

BFS解决方案

class Solution {
  public int numIslands(char[][] grid) {
    if (grid == null || grid.length == 0) {
      return 0;
    }

    int nr = grid.length;
    int nc = grid[0].length;
    int num_islands = 0;

    for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          ++num_islands;
          grid[r][c] = '0'; // mark as visited
          Queue<Integer> neighbors = new LinkedList<>();
          neighbors.add(r * nc + c);
          while (!neighbors.isEmpty()) {
            int id = neighbors.remove();
            int row = id / nc;
            int col = id % nc;
            if (row - 1 >= 0 && grid[row-1][col] == '1') {
              neighbors.add((row-1) * nc + col);
              grid[row-1][col] = '0';
            }
            if (row + 1 < nr && grid[row+1][col] == '1') {
              neighbors.add((row+1) * nc + col);
              grid[row+1][col] = '0';
            }
            if (col - 1 >= 0 && grid[row][col-1] == '1') {
              neighbors.add(row * nc + col-1);
              grid[row][col-1] = '0';
            }
            if (col + 1 < nc && grid[row][col+1] == '1') {
              neighbors.add(row * nc + col+1);
              grid[row][col+1] = '0';
            }
          }
        }
      }
    }

    return num_islands;
  }
}
  

时间复杂度:O(M×N)其中M是行数   和N是列数。

     

空间复杂度:O(min(M,N))因为在最坏的情况下   网格中充满了土地,队列的大小可以长大到   分(M,N)。

2 个答案:

答案 0 :(得分:4)

DFS'时间复杂度与所访问图表的顶点边缘的总数成比例。在这种情况下,有N*M个顶点和略小于4*N*M个边,它们的总和仍为O(N*M)

为什么如此:因为我们在每个方向上精确处理每个边缘一次。递归呼叫立即终止的情况无关紧要,因为该呼叫花费的时间可以在呼叫站点上计算;并且最多一次调用每个有向边,因此O(N*M)

BFS的时间复杂度非常相似。队列的最大长度根本不重要,因为在任何时候我们都不会检查它。队列只获得“追加”和“删除第一”查询,无论队列大小如何,都可以在恒定时间内处理。如果我们需要检查是否已经访问过顶点,我们会在恒定时间内这样做。

DFS 的最坏情况空间复杂度为Theta(N*M):只需采取任何“蛇形”迷宫:

......
#####.
......
.#####
......

这里DFS将被强制遍历整个路径,然后停止并开始释放堆栈。但是,在任何情况下,堆栈上都不会有N*M+1个元素。

BFS 的最坏情况空间复杂性确实不是O(max(N, M)):即使我们正在考虑简单网格,它也是Theta(N*M)。以下是math.stackexchange.com的示例:

enter image description here

如果我们在红点开始BFS,它最终会得到一个包含树的所有叶子的队列,它们的数量与N*M成比例。也可以截断示例的3/4,并使红点出现在左上角。

看起来你读过的解决方案在BFS的最坏情况内存消耗方面是错误的。

答案 1 :(得分:0)

@yeputons:我认为BFS的空间复杂度不会与N * M成正比。 当您说一个队列最大可能具有所有叶子元素(从中心开始时),实际上意味着最大有2 *(N + M)个元素。

并且从一个角落开始时确实为O(min(m,n)),因为添加到队列中的元素数量受到限制。