web-dev-qa-db-fra.com

Complexité temporelle et spatiale DFS et BFS de «Nombre d'îles» sur Leetcode

Ici est la description de la question. Les 2 premières solutions suggérées impliquent DFS et BFS . Cette question se réfère aux deux premières approches: DFS et BFS.

J'ai inclus l'énoncé du problème ici pour une lecture plus facile.

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

Je ne sais pas pourquoi la complexité temporelle pour DFS et BFS est O(rows * columns) pour les deux. Je vois comment c'est le cas où la grille est juste pleine de 0 - nous devons simplement vérifier chaque cellule. Cependant, l'approche DFS n'ajoute-t-elle pas plus de temps à la recherche? Même si nous marquons les cellules que nous avons visitées en les changeant en 0 Dans les méthodes dfs, nous reviendrions toujours sur toutes les cellules en raison des deux boucles externes. Si dfs pouvait avoir une complexité temporelle de O(n) dans le cas d'une grande grille avec de grands numéros de ligne et de colonne, la complexité temporelle ne serait-elle pas O (lignes * colonnes * max [ lignes, cols])? De plus, n'est-ce pas le cas avec l'approche BFS où c'est O(rows * cols * possibleMaxSizeOfQueue)possibleMaxSizeOfQueue pourrait encore être 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);
        }
      }
    }

Quelle est la complexité de l'espace de DFS O(rows*cols)? N'est-il pas possible/courant de considérer l'espace de pile d'appels comme libéré lors du retour d'une branche de récursivité? Quelle est la complexité de l'espace pour BFS O(min(rows, cols))? De mon point de vue, la file d'attente pourrait être pleine de tous les éléments dans le cas d'une grille avec seulement 1 donnant ainsi O(rows*cols) pour la complexité de l'espace BFS.

Solution 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;
  }
}

Complexité temporelle: O (M × N) où M est le nombre de lignes et N est le nombre de colonnes.

Complexité spatiale: pire cas O (M × N) dans le cas où la carte de la grille est remplie de terres où DFS passe par M × N en profondeur.

Solution 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;
  }
}

Complexité temporelle: O (M × N) où M est le nombre de lignes et N est le nombre de colonnes.

Complexité de l'espace: O (min (M, N)) car dans le pire des cas où la grille est remplie de terrains, la taille de la file d'attente peut atteindre min (M, N).

7
heretoinfinity

La complexité temporelle de DFS est proportionnelle au nombre total de sommets et bords du graphique visité. Dans ce cas, il y a N*M Sommets et un peu moins de 4*N*M Arêtes, leur somme est toujours O(N*M).

Pourquoi? Parce que nous traitons chaque Edge exactement une fois dans chaque direction. La situation où un appel récursif est immédiatement terminé n'a pas d'importance car le temps passé pour cet appel peut être comptabilisé sur le site de l'appel; et il y a au plus un appel pour chaque Edge dirigé, d'où O(N*M).

La complexité temporelle de BFS est assez similaire. La longueur maximale de la file d'attente n'a pas d'importance du tout car à aucun moment nous ne l'examinons dans son ensemble. La file d'attente ne reçoit que les requêtes "ajouter" et "supprimer d'abord", qui peuvent être traitées en temps constant quelle que soit la taille de la file d'attente. Si nous devons vérifier si un sommet a déjà été visité, nous le faisons en temps constant.

La complexité de l'espace dans le pire des cas pour DFS est Theta(N*M): il suffit de prendre n'importe quel labyrinthe "au niveau du serpent":

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

Ici, DFS sera obligé de parcourir le chemin dans son intégralité avant qu'il ne s'arrête et commence à libérer la pile. Cependant, en aucun cas, il n'y aura plus de N*M+1 Éléments sur la pile.

La complexité de l'espace dans le pire des cas pour BFS n'est en effet pas O(max(N, M)): c'est Theta(N*M) même si nous envisageons grille simple. Voici un exemple de math.stackexchange.com :

enter image description here

Si nous démarrons BFS au point rouge, il se retrouvera avec une file d'attente qui contient toutes les feuilles de l'arbre, leur nombre est proportionnel à N*M. On peut également tronquer les 3/4 de l'exemple et faire apparaître le point rouge dans le coin supérieur gauche.

Il semble que la solution que vous avez lue soit erronée en ce qui concerne la consommation de mémoire dans le pire des cas de BFS.

7
yeputons