Pular para o conteudo principal

Inverter árvore binária

Como perceber que inverter uma árvore e só trocar esquerda e direita em cada no e deixar a recursão cuidar do resto.

Dada a raiz de uma árvore binaria, inverta a árvore e retorne a raiz.

Inverter significa espelhar esquerda e direita em todos os nos.

Exemplo:

Input:  [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]

O que perceber antes de codar

Erros comuns

Passo 1 - Parar de pensar na árvore inteira de uma vez

Muita gente trava em problema de árvore porque tenta visualizar tudo ao mesmo tempo.

Aqui não precisa.

A pergunta certa e menor:

  • o que precisa acontecer neste no?

Passo 2 - Descobrir a regra local

Em cada no, inverter significa:

  • o que era left vira right
  • o que era right vira left

Só isso.

Passo 3 - Escrever uma versão inicial que deixa a ideia visível

Uma versão inicial valida e construir uma árvore nova espelhada com recursao:

  • copia o valor
  • monta a esquerda a partir da direita antiga
  • monta a direita a partir da esquerda antiga

Funciona e deixa a recursão explicita.

Passo 4 - Perceber que nem precisa criar árvore nova

Se você pode modificar o no atual, basta:

  • inverter os filhos
  • devolver o próprio no

A recursao cuida do resto.

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

Codigo inicial

export function invertTree(root) {
  // root is an object like { val: number, left: ..., right: ... } or null
  // sua solução aqui
  return root
}
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(n)

Espaço: O(h)

Solução 1 - Construir uma árvore nova espelhada

Boa versão inicial porque mostra a regra sem efeito colateral.

export function invertTree(root) {
  if (root === null) {
    return null
  }

  return {
    val: root.val,
    left: invertTree(root.right),
    right: invertTree(root.left),
  }
}

Funciona, mas cria estrutura nova sem necessidade.

Solução 2 - Trocar em-place com recursao e DFS implicita

Agora você reaproveita a própria árvore.

export function invertTree(root) {
  if (root === null) {
    return null
  }

  const left = invertTree(root.left)
  const right = invertTree(root.right)

  root.left = right
  root.right = left

  return root
}

O ponto principal e que a recursão devolve os filhos já invertidos. A partir disso, você só reconecta.

O que dizer na entrevista

Uma explicação curta e boa seria:

Eu penso localmente. Para cada no, preciso trocar esquerda e direita. A recursao resolve os filhos, e depois eu reconecto os dois lados no no atual. Isso visita cada no uma vez em O(n).

Isso mostra que você:

  • não se perde tentando visualizar a árvore inteira
  • sabe transformar regra local em recursão
  • entende o que a função devolve em cada chamada

Quando esse padrão aparece de novo

Esse padrão reaparece quando você precisa:

  • aplicar a mesma regra em todos os nos
  • resolver subarvores e combinar no pai
  • pensar em árvore via recursão local
  • preparar terreno para depth, traversal, BST e LCA

O ponto não e decorar invertTree.

O ponto e aprender a perguntar “o que acontece neste no?”.

Proximo desafio Profundidade máxima de árvore binária Desafio anterior Ciclo em lista encadeada

Desafios relacionados

Artigos relacionados