Swift no LeetCode: por onde começar e como não desistir
Todo desenvolvedor iOS, mais cedo ou mais tarde, bate em uma parede: você faz projetos, envia aplicativos para a AppStore, mas na entrevista te dão um problema sobre árvore binária e você trava. Familiar? LeetCode é aquele treinador que transforma "eu só escrevo UI" em "eu penso com algoritmos". Mas tem um detalhe: a maioria das soluções na internet está em Python ou Java, e Swift é uma linguagem com sua própria filosofia. Neste artigo, vamos analisar como resolver problemas no LeetCode de forma eficiente especificamente em Swift, quais estruturas de dados usar e no que prestar atenção para não perder tempo.
Este artigo é para quem já conhece o básico de Swift, mas quer turbinar o raciocínio algorítmico. Não vamos ensinar sintaxe — vamos aprender a pensar.
Por que Swift é uma excelente escolha para o LeetCode
Muitos pensam que Swift é apenas UIKit e SwiftUI, mas na verdade a linguagem possui capacidades poderosas para problemas algorítmicos:
- Tipos opcionais — trabalho seguro com nil sem crashes inesperados.
- Value types (structs) — cópia previsível, sem surpresas com referências.
- Computação lazy e abordagens funcionais — map, filter, reduce simplificam muito o código.
- Velocidade — Swift compila para código nativo, muitas vezes superando Python em 2-3 vezes.
No entanto, existem armadilhas: por exemplo, arrays em Swift são structs, e copiar um array grande pode ser custoso. Mas falaremos sobre isso separadamente.
Estruturas de dados: o que você precisa saber para Swift no LeetCode
Antes de sair resolvendo problemas, certifique-se de que você trabalha com confiança nas estruturas básicas. Aqui está uma lista de must-know para Swift:
Arrays e slices (Array, ArraySlice)
Arrays em Swift não são apenas listas, mas estruturas poderosas com acesso O(1) por índice. Mas cuidado: inserção/remoção no início é O(n). Use ArraySlice para não copiar dados ao trabalhar com subarrays.
let numbers = [1, 2, 3, 4, 5]let slice = numbers[1..<4] // ArraySlice, sem cópiaprint(slice) // [2, 3, 4]Dicionários e conjuntos (Dictionary, Set)
Para problemas de contagem de frequências, busca de duplicatas ou algoritmos de duas passadas — esses são seus melhores amigos. Lembre-se: Dictionary é uma tabela hash, O(1) na média, mas pode degradar para O(n) com uma função hash ruim.
func twoSum(_ nums: [Int], _ target: Int) -> [Int] { var dict = [Int: Int]() for (i, num) in nums.enumerated() { if let j = dict[target - num] { return [j, i] } dict[num] = i } return []}Pilha e fila (Stack, Queue)
Em Swift não há estruturas nativas de pilha e fila, mas é fácil simulá-las com um array. Para pilha — append e popLast. Para fila, use ArraySlice ou uma lista duplamente encadeada para evitar O(n) no dequeue.
struct Stack<T> { private var array = [T]() mutating func push(_ element: T) { array.append(element) } mutating func pop() -> T? { array.popLast() } var isEmpty: Bool { array.isEmpty }}Listas encadeadas (Linked List)
O LeetCode adora problemas com listas simplesmente encadeadas. Em Swift não há implementação nativa, mas você pode definir uma classe:
class ListNode { var val: Int var next: ListNode? init(_ val: Int) { self.val = val; self.next = nil }}Isso é clássico para problemas de inversão de lista, detecção de ciclo ou remoção de nó.
Padrões algorítmicos para problemas em Swift
Para não reinventar a roda toda vez, memorize alguns padrões que cobrem 80% dos problemas do LeetCode.
Dois ponteiros (Two Pointers)
E