Hay dos enfoques para esta solución, uno sugerido por Leo Polovets:
Aquí hay una implementación para ello:
1. Una forma:
Complejidad de tiempo: O (n * log k) => donde “log k” es el dígito máximo de la base r-radix se utiliza para representar una repetición de un número establecido r-veces.
public class Solution { private static String computeXorBase(String firstNum, String scndNum, int radix) { int lengthFrst = firstNum.length(); int lengthscndNum = scndNum.length(); if (lengthFrst > lengthscndNum) { String swap = firstNum; firstNum = scndNum; scndNum = swap; } lengthFrst = firstNum.length(); lengthscndNum = scndNum.length(); int diffLength = lengthscndNum - lengthFrst; StringBuilder result = new StringBuilder(); for (int i = lengthFrst - 1; i >= 0; i--) { result.insert(0, (Integer.valueOf(firstNum.charAt(i) + "") + Integer.valueOf(scndNum.charAt(diffLength + i) + "")) % radix); } result.insert(0, scndNum.subSequence(0, diffLength)); return result.toString(); } private static String convertToBaseN(int num, int radix) { if (radix < 0) { radix = 10; } if (num < 0) { long l = Math.abs((long) Integer.MIN_VALUE) - Math.abs(num); l = l + 2147483648l; return Long.toString(l, radix); } else { return Integer.toString(num, radix); } } public int singleNumber(int[] A) { if (A == null || A.length <= 2) { return A[0]; } int size = A.length; int radix = 3; String result = convertToBaseN(A[0], radix); for (int i = 1; i < size; i++) { result = computeXorBase(result, convertToBaseN(A[i], radix), radix); } return (int) (long) Long.valueOf(result, radix); } }
2. Otra forma:
implementación en Java,
public class Array3Rpt1Unq{ public static void main(String[] args) { int B[] = {2,4,4,4};//{4,4,2};//{4,4,4,2}; //bit-sets for those which are visited odd(one time only) number of times int ones = 0 ; //bit-sets for those which are visited two times. int twos = 0 ; //just to reset twos and ones if the number are visited three times int not_threes; for( int x:B ) { twos |= ones & x ; ones ^= x ; not_threes = ~(ones & twos) ; ones &= not_threes ; twos &= not_threes ; } //finally ones contains the non-repeated number printf("\n unique element = %d \n", ones ); } }
Explicacion:
El código funciona en una línea similar con la cuestión de "encontrar el elemento que aparece una vez en una matriz, que contiene otros elementos que aparecen dos veces". La solución es XOR todos los elementos y obtienes la respuesta.
Básicamente, hace uso del hecho de que x ^ x = 0. Por lo tanto, todos los elementos emparejados obtienen XOR y desaparecen dejando el elemento solitario.
Dado que la operación XOR es asociativa, conmutativa ... no importa de qué manera los elementos aparezcan en la matriz, todavía obtenemos la respuesta.
Ahora, en la pregunta actual, si aplicamos la idea anterior, no funcionará porque, tenemos que tener cada elemento único apareciendo varias veces. Entonces, en lugar de obtener la respuesta, terminaremos obteniendo XOR de todos los elementos únicos que no es lo que queremos.
Para rectificar este error, el código utiliza 2 variables.
ones: en cualquier momento, esta variable contiene XOR de todos los elementos que tienen
apareció "solo" una vez.
dos: en cualquier momento, esta variable contiene XOR de todos los elementos que tienen
apareció "solo" dos veces.
Entonces, si en algún momento,
1. Aparece un nuevo número: obtiene XOR de la variable "unos".
2. Se repite un número (aparece dos veces): se elimina de "unos" y se envía XOR a la
variable "dos veces".
3. Aparece un número por tercera vez: se elimina de "unos" y "dos veces".
La respuesta final que queremos es el valor presente en "unos", porque contiene el elemento único.
Entonces, si explicamos cómo ocurren los pasos 1 a 3 en el código, ya hemos terminado.
Antes de explicar los 3 pasos anteriores, veamos las últimas tres líneas del código,
not_threes = ~ (unos y dos)
unos & = no_tres
dos & = no_tres
Todo lo que hace es que los 1 comunes entre "unos" y "dos" se convierten a cero.
Para simplificar, en todas las explicaciones a continuación, considere que solo tenemos 4 elementos en la matriz (un elemento único y 3 elementos repetidos, en cualquier orden).
Explicación para el paso 1
————————
Digamos que aparece un nuevo elemento (x).
SITUACIÓN ACTUAL - Ambas variables - "unos" y "dos" no han registrado "x".
Observe la declaración "dos | | unos y x".
Dado que la representación en bits de "x" no está presente en "unos", la condición AND no produce nada. Entonces "dos" no obtiene una representación de "x" en bits.
Pero, en el siguiente paso "ones ^ = x" - "ones" termina agregando bits de "x". Así, el nuevo elemento se graba en "unos" pero no en "dos".
Las últimas 3 líneas de código, como ya se explicó, convierte los "unos" y "dos" b / w comunes de 1 en ceros.
Desde ahora, solo "unos" tiene "x" y no "dos" - las últimas 3 líneas no hacen nada.
Explicación para el paso 2.
————————
Digamos que un elemento (x) aparece dos veces.
SITUACIÓN ACTUAL - "unos" ha grabado "x" pero no "dos".
Ahora, debido a la afirmación, "dos | | unos & x" - "dos" termina obteniendo bits de x.
Pero debido a la declaración, "ones ^ = x" - "ones" elimina "x" de su representación binaria.
Nuevamente, las últimas 3 líneas de código no hacen nada.
Así que, en última instancia, "dos" termina obteniendo bits de "x" y "unos" termina perdiendo bits de "x".
Explicación para el paso 3.
————————-
Digamos que un elemento (x) aparece por tercera vez.
SITUACIÓN ACTUAL - "unos" no tiene una representación en bits de "x" pero sí "dos".
Aunque "unos & x" no produce nada ... "dos" en sí mismo tiene una representación de "x". Entonces, después de esta declaración, "dos" tiene una representación en bits de "x".
Debido a "ones ^ = x", después de este paso, "one" también termina obteniendo una representación en bits de "x".
Ahora las últimas 3 líneas de código eliminan los 1 comunes de "unos" y "dos", que es la representación en bits de "x".
Por lo tanto, tanto "unos" como "dos" terminan perdiendo bits de representación de "x".