Como identificar números duplicados em Lista Java?

Olá pessoal, será que alguém consegue me ajudar nesse algoritmo aqui, li ele mas fiquei meio em dúvida de como proceder?

Dada uma lista ordenada de N + 1 elementos ( Ex.: Se N = 5 - Lista = { 1, 2, 2, 3, 3, 4 }, ou Se N = 2 - Lista = {3, 4, 4} ).
Crie um algoritmo capaz de devolver uma lista com somente os valores repetidos.

Até então eu fiz assim, mas teria algum jeito de não utilizar duas listas finais?

public static void listaOrdenada(List<Integer> lista) {
		List<Integer> lista_unicos = new ArrayList<>();
		List<Integer> lista_repetidos = new ArrayList<>();

		for (int item : lista) {
			if (!lista_unicos.contains(item)) {
				lista_unicos.add(item);
			} else {
				lista_repetidos.add(item);

			}
		}
	}

Valeu Pessoal!

Isso é uma restrição do exercício? Ou você tá preocupado em “economizar” memória?
Pergunto porque sua solução não está ruim e é um código fácil de entender, o que geralmente é mais vantajoso do que tentar otimizar, sem precisar.

Um conselho inicial seria substituir o tipo de lista_unicos de List pra Set, o que vai deixar seu código bem mais eficiente, sem prejudicar a clareza.

Agora, se você quer realmente uma lista só, você pode se aproveitar do fato que a lista é ordenada e simplesmente olhar pro elemento atual e o elemento a frente ao mesmo tempo.
No seu primeiro caso você teria: (1,2), (2,2), (2,3), (3,3), (3,4).
Baseado nessa idéia você consegue escrever um código usando uma lista só.

1 curtida

Se a lista está ordenada, quer dizer que, para cada elemento, o próximo será maior ou igual a ele (nunca será menor).

Então basta fazer um loop, e para cada elemento, verificar se ele é igual ao anterior. Se for, é porque se repete, e aí vc avança até o próximo que seja diferente, e prossegue comparando com o próximo, e assim por diante. Algo assim:

// Mudei o nome do método para algo que faça mais sentido
// Atenção: só funciona se a lista estiver ordenada
public static List<Integer> obterRepetidos(List<Integer> lista) {
    if (lista.isEmpty()) { // se a lista está vazia, nem precisa fazer nada
        return Collections.emptyList(); // retorna uma lista vazia
    }
    List<Integer> repetidos = new ArrayList<>();
    int anterior = lista.get(0); // pega o primeiro elemento
    // começa o loop no segundo elemento (por isso i = 1 em vez de i = 0)
    for (int i = 1; i < lista.size(); i++) {
        int atual = lista.get(i);
        if (atual == anterior) { // número se repete, adiciona na lista
            repetidos.add(atual);
            // avança até mudar de número (ou até chegar no fim da lista)
            while (atual == anterior && i < lista.size() - 1) {
                anterior = atual;
                i++;
                atual = lista.get(i);
            }
        }
        anterior = atual;
    }
    return repetidos;
}

Mas claro, se for para qualquer lista (não necessariamente ordenada), aí use o que sugeriram abaixo.

1 curtida

Da pra ser mais simples.

public static List<Integer> obterRepetidos( List<Integer> lista ) {

    List<Integer> repetidos = new ArrayList<>();
    boolean buscarRepetido = true;

    for ( int i = 0; i < lista.size() - 1; i++ ) {

        if ( buscarRepetido && lista.get( i ).equals( lista.get( i+1 ) ) ) {
            repetidos.add( lista.get( i ) );
            buscarRepetido = false;
        } else {
            buscarRepetido = true;
        }

    }

    return repetidos;

}
1 curtida

Podemos simplificar, usando os recursos de stream…

 public static List<Integer> obterRepetidos(List<Integer> lista){
    Set<Integer> primeiraOCorrencia = new HashSet<>();  // set para guardar primeira ocorrencia de cada numero
    return lista.stream()  // percorre toda a lista
            .filter(e -> !primeiraOCorrencia.add(e))  // filtra pelos que não são adicionados à primeira ocorrencia (repetidos)
            .distinct()       // remove valores duplicados na lista de retorno
            .collect(Collectors.toList());   // adiciona à nova lista
 }
1 curtida