Esta pregunta puede ser antigua, pero no se me ocurrió una respuesta.
Digamos, hay dos listas de diferentes longitudes, que se fusionan en un punto ; ¿Cómo sabemos dónde está el punto de fusión?
Condiciones:
- No sabemos la longitud
- Debemos analizar cada lista solo una vez.
Respuestas:
Si
el siguiente algoritmo sería la solución.
Primero, los números. Suponga que la primera lista es de longitud
a+c
y la segunda es de longitudb+c
, dondec
es la longitud de su "cola" común (después del punto de fusión). Denotémoslos de la siguiente manera:Como no conocemos la longitud, la calcularemos
x
yy
sin iteraciones adicionales; ya verás cómo.Luego, iteramos cada lista y las invertimos mientras iteramos. Si ambos iteradores alcanzan el punto de fusión al mismo tiempo, lo averiguaremos mediante una mera comparación. De lo contrario, un puntero llegará al punto de fusión antes que el otro.
Después de eso, cuando el otro iterador alcance el punto de fusión, no procederá a la cola común. En su lugar, volverá al comienzo anterior de la lista que había alcanzado el punto de fusión antes. Por lo tanto, antes de que llegue al final de la lista modificada (es decir, el comienzo anterior de la otra lista),
a+b+1
sumará las iteraciones. Vamos a llamarloz+1
.El puntero que llegó primero al punto de fusión seguirá iterando hasta que llegue al final de la lista. El número de iteraciones que realizó debe calcularse y es igual a
x
.Luego, este puntero se repite e invierte las listas nuevamente. ¡Pero ahora no volverá al principio de la lista desde la que comenzó originalmente! En cambio, irá al principio de la otra lista. El número de iteraciones que realizó debe calcularse y ser igual
y
.Entonces conocemos los siguientes números:
De lo que determinamos que
Lo que resuelve el problema.
fuente
El siguiente es, con mucho, el mejor de todos los que he visto: O (N), sin contadores. Lo conseguí durante una entrevista a un candidato SN en VisionMap .
Cree un puntero interactivo como este: avanza cada vez hasta el final, luego salta al principio de la lista opuesta, y así sucesivamente. Crea dos de estos, apuntando a dos cabezas. Avance cada uno de los indicadores en 1 cada vez, hasta que se encuentren. Esto sucederá después de una o dos pasadas.
Todavía utilizo esta pregunta en las entrevistas, pero para ver cuánto tiempo le toma a alguien entender por qué funciona esta solución.
fuente
a-b-c-x-y-z
yp-q-x-y-z
. ruta del primer punteroa,b,c,x,y,z,p,q,x
, ruta del segundo punterop,q,x,y,z,a,b,c,x
La respuesta de Pavel requiere la modificación de las listas , así como la iteración de cada lista dos veces.
Aquí hay una solución que solo requiere iterar cada lista dos veces (la primera vez para calcular su longitud; si se proporciona la longitud, solo necesita iterar una vez).
La idea es ignorar las entradas iniciales de la lista más larga (el punto de fusión no puede estar allí), de modo que los dos punteros estén a la misma distancia del final de la lista. Luego muévalos hacia adelante hasta que se fusionen.
Esto es asintóticamente lo mismo (tiempo lineal) que mi otra respuesta, pero probablemente tiene constantes más pequeñas, por lo que probablemente sea más rápido. Pero creo que mi otra respuesta es más genial.
fuente
Bueno, si sabes que se fusionarán:
Digamos que comienzas con:
1) Revise la primera lista configurando cada puntero siguiente en NULL.
Ahora tu tienes:
2) Ahora revise la segunda lista y espere hasta que vea un NULL, ese es su punto de fusión.
Si no puede estar seguro de que se fusionen, puede usar un valor centinela para el valor del puntero, pero eso no es tan elegante.
fuente
Si pudiéramos iterar listas exactamente dos veces, entonces puedo proporcionar un método para determinar el punto de fusión:
fuente
Aquí hay una solución, computacionalmente rápida (itera cada lista una vez) pero usa mucha memoria:
fuente
Puede utilizar un conjunto de Nodos. Repita una lista y agregue cada nodo al conjunto. Luego, recorra la segunda lista y, para cada iteración, verifique si el nodo existe en el conjunto. Si es así, ha encontrado su punto de fusión :)
fuente
Podría decirse que esto viola la condición "analizar cada lista solo una vez", pero implementa el algoritmo de la tortuga y la liebre (que se usa para encontrar el punto de fusión y la duración del ciclo de una lista cíclica) para comenzar en la Lista A, y cuando llegue a NULL en el Al final, finge que es un puntero al principio de la lista B, creando así la apariencia de una lista cíclica. A continuación, el algoritmo le dirá exactamente qué tan abajo de la Lista A está la fusión (la variable 'mu' según la descripción de Wikipedia).
Además, el valor "lambda" le indica la longitud de la lista B y, si lo desea, puede calcular la longitud de la lista A durante el algoritmo (cuando redirige el enlace NULL).
fuente
Tal vez estoy simplificando demasiado esto, pero simplemente iterar la lista más pequeña y usar los últimos nodos
Link
como punto de fusión.Entonces, ¿dónde
Data->Link->Link == NULL
está el punto final, dandoData->Link
como punto de fusión (al final de la lista).EDITAR:
De acuerdo, a partir de la imagen que publicó, analice las dos listas, la más pequeña primero. Con la lista más pequeña puede mantener las referencias al siguiente nodo. Ahora, cuando analice la segunda lista, haga una comparación en la referencia para encontrar donde Reference [i] es la referencia en LinkedList [i] -> Link. Esto le dará el punto de fusión. Es hora de explicar con imágenes (superponer los valores en la imagen del OP).
Tiene una lista vinculada (las referencias se muestran a continuación):
A->B->C->D->E
Tienes una segunda lista vinculada:
1->2->
Con la lista combinada, las referencias serían las siguientes:
1->2->D->E->
Por lo tanto, mapea la primera lista "más pequeña" (ya que la lista combinada, que es lo que estamos contando tiene una longitud de 4 y la lista principal 5)
Recorra la primera lista, mantenga una referencia de referencias.
La lista contendrá las siguientes referencias
Pointers { 1, 2, D, E }
.Ahora pasamos por la segunda lista:
Seguro, mantiene una nueva lista de punteros, pero eso no está fuera de la especificación. Sin embargo, la primera lista se analiza exactamente una vez, y la segunda lista solo se analizará completamente si no hay un punto de fusión. De lo contrario, terminará antes (en el punto de fusión).
fuente
Probé un caso de combinación en mi FC9 x86_64 e imprimí cada dirección de nodo como se muestra a continuación:
Tenga en cuenta porque había alineado la estructura del nodo, por lo que cuando malloc () un nodo, la dirección está alineada con 16 bytes, vea los 4 bits como mínimo. Los bits mínimos son 0, es decir, 0x0 o 000b. Entonces, si también está en el mismo caso especial (dirección de nodo alineada), puede usar estos 4 bits como mínimo. Por ejemplo, cuando recorra ambas listas de principio a fin, establezca 1 o 2 de los 4 bits de la dirección del nodo visitante, es decir, establezca una bandera;
Tenga en cuenta que los indicadores anteriores no afectarán la dirección del nodo real, sino solo el valor del puntero del nodo GUARDADO.
Una vez encontrado, alguien había establecido los bits de la bandera, entonces el primer nodo encontrado debería ser el punto de fusión. una vez hecho esto, restauraría la dirección del nodo borrando los bits de bandera que había establecido. mientras que una cosa importante es que debe tener cuidado al iterar (por ejemplo, nodo = nodo-> siguiente) para limpiar. recuerde que ha establecido bits de bandera, así que hágalo de esta manera
Debido a que esta propuesta restaurará las direcciones de nodo modificadas, podría considerarse como "sin modificación".
fuente
Puede haber una solución simple pero requerirá un espacio auxiliar. La idea es recorrer una lista y almacenar cada dirección en un mapa hash, ahora recorrer la otra lista y hacer coincidir si la dirección se encuentra en el mapa hash o no. Cada lista se recorre solo una vez. No hay modificaciones en ninguna lista. La longitud aún se desconoce. Espacio auxiliar utilizado: O (n) donde 'n' es la longitud de la primera lista recorrida.
fuente
esta solución itera cada lista solo una vez ... no se requiere modificación de la lista también ... aunque puede quejarse del espacio ...
1) Básicamente, itera en list1 y almacena la dirección de cada nodo en una matriz (que almacena el valor int sin firmar)
2) Luego itera list2, y para la dirección de cada nodo ---> busca en la matriz que encuentra una coincidencia o no ... si lo hace, entonces este es el nodo de fusión
Espero que sea una solución válida ...
fuente
No es necesario modificar ninguna lista. Existe una solución en la que solo tenemos que recorrer cada lista una vez.
fuente
fuente
Aquí hay una solución ingenua, no es necesario recorrer listas completas.
si su nodo estructurado tiene tres campos como
digamos que tiene dos cabezas (head1 y head2) apuntando a la cabeza de dos listas.
Recorre ambas listas al mismo ritmo y coloca la bandera = 1 (bandera visitada) para ese nodo,
fuente
Qué tal esto:
Si solo se le permite atravesar cada lista solo una vez, puede crear un nuevo nodo, atravesar la primera lista para que cada nodo apunte a este nuevo nodo y atravesar la segunda lista para ver si algún nodo apunta a su nuevo nodo ( ese es tu punto de fusión). Si el segundo recorrido no conduce a su nuevo nodo, las listas originales no tienen un punto de fusión.
Si se le permite recorrer las listas más de una vez, entonces puede recorrer cada lista para encontrar nuestras longitudes y si son diferentes, omita los nodos "extra" al comienzo de la lista más larga. Luego, simplemente recorra ambas listas paso a paso y encuentre el primer nodo de fusión.
fuente
Pasos en Java:
fuente
Podemos resolverlo de manera eficiente introduciendo el campo "isVisited". Recorra la primera lista y establezca el valor "isVisited" en "verdadero" para todos los nodos hasta el final. Ahora comience desde el segundo y encuentre el primer nodo donde la bandera es verdadera y Boom, es su punto de fusión.
fuente
Paso 1: encuentre la longitud de ambas listas Paso 2: Encuentre la diferencia y mueva la lista más grande con la diferencia Paso 3: Ahora ambas listas estarán en una posición similar. Paso 4: iterar a través de la lista para encontrar el punto de fusión
fuente
fuente
Utilice Mapa o Diccionario para almacenar la dirección frente al valor del nodo. si la dirección ya existe en el Mapa / Diccionario, entonces el valor de la clave es la respuesta. Hice esto:
fuente
Solución de complejidad AO (n). Pero basado en una suposición.
La suposición es: ambos nodos solo tienen números enteros positivos.
lógica: convierte todo el número entero de list1 en negativo. Luego, recorra la lista2 hasta que obtenga un número entero negativo. Una vez encontrado => tómalo, cambia el signo de nuevo a positivo y regresa.
fuente
Podemos usar dos punteros y movernos de tal manera que si uno de los punteros es nulo lo apuntamos al encabezado de la otra lista y lo mismo para el otro, de esta manera si las longitudes de la lista son diferentes se encontrarán en la segunda pasada . Si la longitud de list1 es n y list2 es m, su diferencia es d = abs (nm). Cubrirán esta distancia y se encontrarán en el punto de fusión.
Código:
fuente
Puede agregar los nodos de
list1
a un hashset y el bucle a través del segundo y si algún nodo delist2
ya está presente en el conjunto. Si es así, entonces ese es el nodo de fusiónfuente
Solución usando javascript
fuente
Si se permite editar la lista vinculada,
fuente