Detecção de Elementos Duplicados em Arrays com C++

A identificação de elementos repetidos em coleções de dados é um problema fundamental em ciência da computação, frequentemente encontrado em desafios de algoritmos como os do LeetCode. Veremos a seguir diferentes estratégias para resolver duas variações desse problema: a detecção simples de duplicatas e a busca por duplicatas dentro de um intervalo específico k.

Problema 1: Verificação de Existência de Duplicatas

O objetivo é determinar se qualquer valor aparece ao menos duas vezes em um array de inteiros. A função deve retornar true se houver duplicatas e false caso todos os elementos sejam distintos.

Abordagem 1: Ordenação de Vetores

Ao ordenar o array, todos os elementos iguais ficam adjacentes. Isso permite identificar duplicatas com uma única passagem após a ordenação. A complexidade de tempo é definida pelo algoritmo de sort, sendo O(n log n).


class Solution {
public:
    bool containsDuplicate(vector<int>& lista) {
        if (lista.size() <= 1) return false;
        
        // Ordenação in-place
        std::sort(lista.begin(), lista.end());
        
        for (size_t i = 0; i < lista.size() - 1; ++i) {
            if (lista[i] == lista[i + 1]) {
                return true;
            }
        }
        return false;
    }
};

Abordagem 2: Utilizando Tabelas de Hash (Unordered Set)

Esta abordagem utiliza uma estrutura de dados de conjunto (hash set) para armazenar elementos já visitados. A busca em um unordered_set tem tempo médio constante, resultando em uma complexidade O(n).


class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> elementosVistos;
        
        for (const int& valor : nums) {
            // Se o elemento já existe no set, encontramos uma duplicata
            if (elementosVistos.find(valor) != elementosVistos.end()) {
                return true;
            }
            elementosVistos.insert(valor);
        }
        return false;
    }
};

Problema 2: Duplicatas em Intervalo Limitado (K)

Nesta variação, precisamos encontrar dois índices distintos i e j tais que nums[i] == nums[j] e a diferença absoluta entre os índices seja, no máximo, k.

Abordagem 1: Janela Deslizante com Hash Set

Podemos manter um conjunto contendo apenas os elementos que estão dentro da janela de distância k. Conforme avançamos no array, removemos o elemento que saiu do alcance da janela e verificamos se o novo elemento já existe no conjunto atual.


class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& arr, int k) {
        unordered_set<int> janela;
        
        for (int i = 0; i < arr.size(); ++i) {
            // Mantém o tamanho da janela removendo elementos fora do alcance k
            if (i > k) {
                janela.erase(arr[i - k - 1]);
            }
            
            // Tenta inserir; se já existir, insert().second será false
            if (!janela.insert(arr[i]).second) {
                return true;
            }
        }
        return false;
    }
};

Abordagem 2: Mapeamento de Último Índice

Outra estratégia eficiente utiliza um unordered_map para armazenar o valor do elemento como chave e seu índice mais recente como valor. Ao encontrar um número que já está no mapa, calculamos a distância entre o índice atual e o anterior.


class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_map<int, int> mapaIndices;
        
        for (int i = 0; i < nums.size(); ++i) {
            int numAtual = nums[i];
            
            if (mapaIndices.count(numAtual)) {
                if (i - mapaIndices[numAtual] <= k) {
                    return true;
                }
            }
            // Atualiza ou insere o índice atual do número
            mapaIndices[numAtual] = i;
        }
        return false;
    }
};

Considerações sobre Performance

Para o primeiro problema, a solução com unordered_set é geralmente mais rápida devido à complexidade linear, embora consuma mais memória que a ordenação. No segundo problema, a técnica de janela deslizante otimiza o uso de memória, mantendo no máximo k elementos no conjunto, o que é ideal quando k é significativamente menor que o tamanho total do array.

Tags: cpp algorithms LeetCode hash-table data-structures

Publicado em 7-5 04:59