Pular para o conteudo principal

Número de ilhas

Como enxergar cada celula como no de um grafo e usar busca em profundidade ou em largura para consumir uma ilha inteira de uma vez.

Dada uma grade 2D composta por '1' (terra) e '0' (agua), retorne o número de ilhas.

Uma ilha e formada por terras conectadas horizontal ou verticalmente.

Exemplo:

Input:
[
  ['1','1','0','0','0'],
  ['1','1','0','0','0'],
  ['0','0','1','0','0'],
  ['0','0','0','1','1']
]

Output: 3

O que perceber antes de codar

Erros comuns

Passo 1 - Parar de ver isso como só uma matriz

Esse problema fica mais simples quando você troca o nome mental dele.

Em vez de "matriz de 1 e 0", pense:

  • cada celula de terra e um no
  • vizinhos em cima, baixo, esquerda e direita sao arestas

Agora você esta contando componentes conectados.

Passo 2 - Escrever a regra de contagem

Se você esta varrendo a grade e encontra uma terra ainda não visitada:

  • achou uma ilha nova
  • incrementa a resposta
  • consome toda a ilha antes de seguir

Passo 3 - Fazer a versão inicial com visitados

Uma versão inicial boa e:

Isso deixa a estrutura do problema bem explicita.

Passo 4 - Perceber que a própria grade pode virar o visitado

Em muitos casos, você não precisa de estrutura extra.

Pode marcar a terra já processada como agua e continuar.

O editor interativo precisa de JavaScript. Voce ainda pode ler o desafio e copiar o codigo inicial abaixo.

Codigo inicial

export function numIslands(grid: string[][]): number {
  // sua solução aqui
  return 0
}
solution.ts
Travado? Dicas disponiveis.

Ainda não resolveu?

Ver a solução agora pode reduzir o aprendizado. Vale a pena tentar mais um pouco.

Abrir a solucao de referencia

Sem JavaScript, a solucao de referencia aparece inline em vez de um dialogo.

Solução

Complexidade final

Tempo: O(rows * cols)

Espaço: O(rows * cols)

Solução 1 - Busca em profundidade (DFS) com conjunto hash de visitados

Boa versão inicial para deixar claro que o problema e de componente conectada.

export function numIslands(grid: string[][]): number {
  const rows = grid.length
  const cols = grid[0]?.length ?? 0
  const visited = new Set<string>()
  let islands = 0

  function dfs(row: number, col: number) {
    if (
      row < 0 ||
      row >= rows ||
      col < 0 ||
      col >= cols ||
      grid[row][col] === '0'
    ) {
      return
    }

    const key = `${row},${col}`

    if (visited.has(key)) {
      return
    }

    visited.add(key)

    dfs(row + 1, col)
    dfs(row - 1, col)
    dfs(row, col + 1)
    dfs(row, col - 1)
  }

  for (let row = 0; row < rows; row += 1) {
    for (let col = 0; col < cols; col += 1) {
      if (grid[row][col] === '1' && !visited.has(`${row},${col}`)) {
        islands += 1
        dfs(row, col)
      }
    }
  }

  return islands
}

Funciona bem. Mas da para usar a própria grade como marcador.

Solução 2 - Busca em profundidade (DFS) transformando a grade na estrutura de visitados

Agora o visitado fica embutido no próprio input.

export function numIslands(grid: string[][]): number {
  const rows = grid.length
  const cols = grid[0]?.length ?? 0
  let islands = 0

  function dfs(row: number, col: number) {
    if (
      row < 0 ||
      row >= rows ||
      col < 0 ||
      col >= cols ||
      grid[row][col] === '0'
    ) {
      return
    }

    grid[row][col] = '0'

    dfs(row + 1, col)
    dfs(row - 1, col)
    dfs(row, col + 1)
    dfs(row, col - 1)
  }

  for (let row = 0; row < rows; row += 1) {
    for (let col = 0; col < cols; col += 1) {
      if (grid[row][col] === '1') {
        islands += 1
        dfs(row, col)
      }
    }
  }

  return islands
}

O ponto forte aqui e a leitura de componente conectada, não o fato de ser busca em profundidade (DFS) especificamente.

O que dizer na entrevista

Uma explicação curta e boa seria:

Eu trato cada terra como no de um grafo em grade. Quando encontro uma terra ainda não visitada, isso significa uma nova ilha. Entao incremento a resposta e faco busca em profundidade (DFS) para consumir toda a componente conectada. Assim cada celula e visitada no máximo uma vez.

Isso mostra que você:

  • traduziu o formato para um modelo de grafo
  • separou a regra de contagem da regra de exploração
  • explicou por que a resposta não duplica ilhas

Quando esse padrão aparece de novo

Esse padrão reaparece quando você precisa:

O ponto não e decorar esse problema.

O ponto e aprender a ver grafos escondidos em grades.

Proximo desafio Validar árvore binária de busca Desafio anterior Troco com moedas

Desafios relacionados

Artigos relacionados