← Back to home

Invert Binary Tree

By Pscodium · 8/4/2026 · 3 views

Invert Binary Tree — Entendendo Árvores Binárias na Prática

Um dos problemas mais conhecidos para quem está estudando estruturas de dados e algoritmos é o Invert Binary Tree, também conhecido como inversão de uma árvore binária.

Esse problema ficou especialmente famoso por aparecer em entrevistas técnicas e por ser um excelente exercício para entender:

  • Árvores binárias
  • Recursão
  • Estruturas de dados
  • Travessia de árvores
  • Pensamento algorítmico

Mas antes de resolver o problema, precisamos entender:

O que exatamente é uma árvore binária?


1. O que é uma árvore binária?

Uma árvore binária é uma estrutura de dados formada por nós (nodes).

Cada nó pode possuir, no máximo:

2 filhos

Esses filhos são chamados de:

Left  → Filho da esquerda

Right → Filho da direita

Por exemplo:

        4
       / \
      2   7
     / \ / \
    1  3 6  9

Nesse exemplo:

4

é a raiz (root) da árvore.

O nó 4 possui dois filhos:

2 → esquerda

7 → direita

O nó 2 também possui dois filhos:

1 → esquerda

3 → direita

E assim por diante.


2. Por que é chamada de "árvore"?

O nome vem da forma como a estrutura é organizada.

Temos:

        ROOT
         │
         ▼
       PARENT
       /    \
      ▼      ▼
    CHILD  CHILD

Diferente de uma árvore do mundo real, ela normalmente é desenhada com a raiz no topo e os filhos abaixo.

Por exemplo:

             10
           /    \
          5      20
         / \    /  \
        2   7  15  30

A estrutura começa em um único ponto:

10

E vai se ramificando.

Por isso o nome:

Tree (árvore)


3. O que é um Node?

Cada elemento da árvore é um Node.

Um Node de uma árvore binária normalmente possui:

value
left
right

Em TypeScript, podemos representar assim:

class TreeNode {
  value: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(
    value: number,
    left: TreeNode | null = null,
    right: TreeNode | null = null
  ) {
    this.value = value;
    this.left = left;
    this.right = right;
  }
}

Podemos criar uma árvore:

const root = new TreeNode(
  4,
  new TreeNode(
    2,
    new TreeNode(1),
    new TreeNode(3)
  ),
  new TreeNode(
    7,
    new TreeNode(6),
    new TreeNode(9)
  )
);

Que representa:

        4
       / \
      2   7
     / \ / \
    1  3 6  9

4. O problema do LeetCode

O problema Invert Binary Tree pede para inverter uma árvore binária.

Dada a árvore:

        4
       / \
      2   7
     / \ / \
    1  3 6  9

Precisamos obter:

        4
       / \
      7   2
     / \ / \
    9  6 3  1

Perceba o que aconteceu.

Em cada nó:

left

e:

right

foram trocados.

Antes:

Node
├── Left
└── Right

Depois:

Node
├── Right
└── Left

5. A ideia da solução

A solução é surpreendentemente simples.

Para cada nó:

1. Trocar left e right
2. Fazer o mesmo no filho esquerdo
3. Fazer o mesmo no filho direito

Por exemplo:

        4
       / \
      2   7

Trocamos:

        4
       / \
      7   2

Agora precisamos fazer a mesma coisa em:

7

e:

2

Esse processo continua até chegarmos aos nós que não possuem filhos.


6. A solução recursiva

Em TypeScript:

function invertTree(root: TreeNode | null): TreeNode | null {
  if (root === null) {
    return null;
  }

  const temp = root.left;

  root.left = root.right;
  root.right = temp;

  invertTree(root.left);
  invertTree(root.right);

  return root;
}

A lógica principal é:

const temp = root.left;

root.left = root.right;
root.right = temp;

Estamos simplesmente trocando os dois filhos.

Depois:

invertTree(root.left);
invertTree(root.right);

Aplicamos a mesma lógica para os filhos.


7. Entendendo a recursão

Imagine esta árvore:

        4
       / \
      2   7

Chamamos:

invertTree(root);

O root é:

4

Trocamos:

2 ↔ 7

Resultado:

        4
       / \
      7   2

Agora chamamos:

invertTree(7);

Depois:

invertTree(2);

Se o nó não possui filhos:

7

A função simplesmente termina.

O processo acontece para todos os nós da árvore.


8. Visualizando passo a passo

Árvore original:

        4
       / \
      2   7
     / \ / \
    1  3 6  9

Primeiro:

        4
       / \
      7   2
     / \ / \
    6  9 1  3

Depois, invertendo os filhos de 7:

        4
       / \
      7   2
     / \ / \
    9  6 1  3

Depois, invertendo os filhos de 2:

        4
       / \
      7   2
     / \ / \
    9  6 3  1

Resultado final:

        4
       / \
      7   2
     / \ / \
    9  6 3  1

9. Complexidade

Se a árvore possui n nós:

Time Complexity: O(n)

Precisamos visitar cada nó uma vez.

Em relação à memória:

Space Complexity: O(h)

Onde h é a altura da árvore.

Isso acontece porque utilizamos a pilha de chamadas da recursão.

Em uma árvore balanceada:

O(log n)

Em uma árvore completamente desbalanceada:

O(n)

Por exemplo:

1
 \
  2
   \
    3
     \
      4

Nesse caso, a árvore se comporta praticamente como uma lista.


10. Existe uma solução iterativa?

Sim.

Podemos utilizar uma fila:

function invertTree(root: TreeNode | null): TreeNode | null {
  if (root === null) {
    return null;
  }

  const queue: TreeNode[] = [root];

  while (queue.length > 0) {
    const node = queue.shift()!;

    // Troca os filhos
    [node.left, node.right] = [node.right, node.left];

    if (node.left !== null) {
      queue.push(node.left);
    }

    if (node.right !== null) {
      queue.push(node.right);
    }
  }

  return root;
}

Essa abordagem utiliza uma travessia conhecida como:

Breadth-First Search (BFS)

A árvore é percorrida por níveis:

        4        ← Nível 1
       / \
      2   7      ← Nível 2
     / \ / \
    1  3 6  9    ← Nível 3

11. Mas onde isso é usado na vida real?

O problema do LeetCode é principalmente um exercício de algoritmos.

Na prática, provavelmente você não vai receber uma tarefa dizendo:

"Inverta essa árvore binária."

Porém, o conceito de percorrer e modificar estruturas de árvores aparece em diversos sistemas reais.

Um exemplo interessante é uma árvore de componentes de uma interface gráfica.

Imagine uma aplicação que possui:

Aplicação
   │
   ├── Header
   │
   ├── Main
   │    ├── Sidebar
   │    └── Content
   │
   └── Footer

Essa estrutura pode ser representada como uma árvore:

             App
          /   |   \
         /    |    \
     Header  Main  Footer
              / \
             /   \
        Sidebar Content

Frameworks e bibliotecas de UI trabalham constantemente com estruturas hierárquicas desse tipo.


12. Um exemplo prático: inverter uma árvore de componentes

Imagine que temos um menu lateral:

Menu
├── Home
├── Produtos
│   ├── Notebooks
│   └── Celulares
└── Contato

Agora imagine uma aplicação que precisa mudar a estrutura de navegação de uma interface para uma versão espelhada.

Por exemplo, em uma aplicação que suporta idiomas RTL:

Right-to-Left

Como:

  • Árabe
  • Hebraico

A interface pode precisar inverter a posição de determinados elementos.

Uma estrutura:

Sidebar
    │
    ├── Menu
    │
    └── Content

Pode se tornar:

Content
    │
    └── Menu

Embora aplicações reais normalmente utilizem técnicas específicas de CSS e layout para isso, o conceito por trás é semelhante:

Percorrer uma estrutura hierárquica e modificar a relação entre seus elementos.


13. Outro exemplo: árvore de pastas

Um exemplo ainda mais fácil de visualizar é um sistema de arquivos.

Imagine:

Projeto
├── src
│   ├── components
│   └── services
├── tests
└── package.json

Isso também é uma árvore.

Podemos representar:

type FileNode = {
  name: string;
  children: FileNode[];
};

Agora podemos percorrer a estrutura recursivamente:

function printTree(node: FileNode, level = 0) {
  console.log(" ".repeat(level * 2) + node.name);

  for (const child of node.children) {
    printTree(child, level + 1);
  }
}

Isso permite:

Projeto
  src
    components
    services
  tests
  package.json

Esse tipo de algoritmo é utilizado em:

  • Exploradores de arquivos
  • IDEs
  • Sistemas de gerenciamento de documentos
  • Menus hierárquicos
  • Categorias
  • Sistemas de permissões

14. E se quiséssemos inverter uma árvore de pastas?

Imagine:

Projeto
├── src
│   ├── components
│   └── services
└── tests

Em uma árvore binária, cada nó possui:

left
right

Então podemos inverter:

Projeto
├── tests
└── src
    ├── services
    └── components

Uma implementação seria:

function invertTree(node: FileNode): FileNode {
  if (node.children.length === 0) {
    return node;
  }

  node.children.reverse();

  for (const child of node.children) {
    invertTree(child);
  }

  return node;
}

Aqui temos a mesma ideia do problema do LeetCode:

1. Modificar o nó atual
2. Percorrer os filhos
3. Repetir recursivamente

A diferença é que uma árvore de arquivos pode ter vários filhos, enquanto uma árvore binária possui no máximo dois.


15. O verdadeiro aprendizado do problema

O objetivo do problema Invert Binary Tree não é necessariamente aprender a inverter árvores.

O principal aprendizado é entender como trabalhar com estruturas recursivas.

A ideia é:

Resolver o problema atual
        │
        ▼
Delegar o mesmo problema
para os filhos
        │
        ▼
Repetir até chegar
ao caso base

No caso da árvore:

              ROOT
             /    \
            /      \
         LEFT      RIGHT
          /          \
       LEFT         RIGHT

A mesma lógica é aplicada em cada nível.

Esse padrão aparece em vários problemas:

  • Árvores binárias
  • Árvores de arquivos
  • DOM
  • Menus
  • Estruturas de categorias
  • ASTs de compiladores
  • Estruturas de diretórios
  • Sistemas hierárquicos

Conclusão

Uma árvore binária é uma estrutura de dados em que cada nó possui, no máximo, dois filhos:

        Node
       /    \
    Left   Right

O problema Invert Binary Tree consiste em trocar esses dois filhos em todos os nós:

Antes:

        4
       / \
      2   7


Depois:

        4
       / \
      7   2

A solução mais comum utiliza recursão:

function invertTree(root: TreeNode | null): TreeNode | null {
  if (root === null) {
    return null;
  }

  [root.left, root.right] = [root.right, root.left];

  invertTree(root.left);
  invertTree(root.right);

  return root;
}

A grande lição é que recursão combina naturalmente com estruturas hierárquicas.

Quando encontramos uma estrutura que possui:

Pai
 ├── Filho
 │    ├── Neto
 │    └── Neto
 └── Filho

podemos frequentemente resolver o problema seguindo uma estratégia simples:

Resolva o nó atual e aplique a mesma lógica recursivamente aos seus filhos.

É exatamente esse padrão de pensamento que torna problemas como o Invert Binary Tree tão importantes em entrevistas e no estudo de estruturas de dados.


Comments

No comments yet.