Esta pergunta pode ser antiga, mas não consegui pensar em uma resposta.
Digamos, há duas listas de comprimentos diferentes, mescladas em um ponto ; como sabemos onde está o ponto de fusão?
Condições:
- Não sabemos o comprimento
- Devemos analisar cada lista apenas uma vez.
algorithm
linked-list
data-structures
rplusg
fonte
fonte
Respostas:
E se
o seguinte algoritmo seria a solução.
Primeiro, os números. Suponha que a primeira lista seja longa
a+c
e a segunda seja longab+c
, ondec
é o comprimento de sua "cauda" comum (após o ponto de fusão). Vamos denotá-los da seguinte forma:Como não sabemos o comprimento, calcularemos
x
ey
sem iterações adicionais; você verá como.Em seguida, iteramos cada lista e as revertemos durante a iteração! Se os dois iteradores alcançarem o ponto de fusão ao mesmo tempo, descobrimos isso por meio de uma simples comparação. Caso contrário, um ponteiro alcançará o ponto de fusão antes do outro.
Depois disso, quando o outro iterador atingir o ponto de fusão, ele não prosseguirá para a cauda comum. Em vez disso, irá voltar para o início anterior da lista que atingiu o ponto de fusão antes! Portanto, antes de atingir o final da lista alterada (ou seja, o primeiro início da outra lista), ele fará as
a+b+1
iterações totais. Vamos encerrarz+1
.O ponteiro que alcançou o ponto de mesclagem primeiro, continuará iterando, até atingir o final da lista. O número de iterações feitas deve ser calculado e é igual a
x
.Em seguida, esse ponteiro itera de volta e reverte as listas novamente. Mas agora não vai voltar para o início da lista da qual originalmente começou! Em vez disso, irá para o início da outra lista! O número de iterações feitas deve ser calculado e igual a
y
.Portanto, sabemos os seguintes números:
A partir do qual determinamos que
O que resolve o problema.
fonte
O que segue é de longe o maior de todos que já vi - O (N), sem contadores. Eu consegui durante uma entrevista a um candidato a SN na VisionMap .
Faça um ponteiro de interação como este: ele avança todas as vezes até o fim, e então pula para o início da lista oposta e assim por diante. Crie dois desses, apontando para duas cabeças. Avance cada um dos ponteiros em 1 a cada vez, até que eles se encontrem. Isso acontecerá após uma ou duas passagens.
Eu ainda uso essa pergunta nas entrevistas - mas para ver quanto tempo leva para alguém entender porque essa solução funciona.
fonte
a-b-c-x-y-z
ep-q-x-y-z
. caminho do primeiro ponteiroa,b,c,x,y,z,p,q,x
, caminho do segundo ponteirop,q,x,y,z,a,b,c,x
A resposta de Pavel requer modificação das listas , bem como iterar cada lista duas vezes.
Aqui está uma solução que requer apenas a iteração de cada lista duas vezes (a primeira vez para calcular seu comprimento; se o comprimento for fornecido, você só precisa iterar uma vez).
A ideia é ignorar as entradas iniciais da lista mais longa (o ponto de fusão não pode estar lá), de modo que os dois ponteiros fiquem a uma distância igual do final da lista. Em seguida, mova-os para a frente até que se fundam.
Isso é assintoticamente o mesmo (tempo linear) que minha outra resposta, mas provavelmente tem constantes menores, então é provavelmente mais rápido. Mas acho que minha outra resposta é mais legal.
fonte
Bem, se você sabe que eles vão se fundir:
Digamos que você comece com:
1) Percorra a primeira lista definindo cada ponteiro seguinte como NULL.
Agora você tem:
2) Agora vá até a segunda lista e espere até ver um NULL, que é o seu ponto de fusão.
Se você não tiver certeza de que eles se fundem, pode usar um valor de sentinela para o valor do ponteiro, mas isso não é tão elegante.
fonte
Se pudéssemos iterar as listas exatamente duas vezes, posso fornecer um método para determinar o ponto de fusão:
fonte
Aqui está uma solução, computacionalmente rápida (itera cada lista uma vez), mas usa muita memória:
fonte
Você pode usar um conjunto de nós. Faça a iteração em uma lista e adicione cada nó ao conjunto. Em seguida, itere através da segunda lista e para cada iteração, verifique se o Nó existe no conjunto. Em caso afirmativo, você encontrou seu ponto de fusão :)
fonte
Isso viola a condição "analise cada lista apenas uma vez", mas implemente o algoritmo da tartaruga e da lebre (usado para encontrar o ponto de fusão e a duração do ciclo de uma lista cíclica), então você começa na Lista A e quando atinge o NULL no end você finge que é um ponteiro para o início da lista B, criando assim a aparência de uma lista cíclica. O algoritmo então dirá exatamente a que ponto abaixo da Lista A está a mesclagem (a variável 'mu' de acordo com a descrição da Wikipedia).
Além disso, o valor "lambda" informa o comprimento da lista B e, se desejar, você pode calcular o comprimento da lista A durante o algoritmo (quando redirecionar o link NULL).
fonte
Talvez eu esteja simplificando demais isso, mas simplesmente itere a menor lista e use os últimos nós
Link
como o ponto de fusão?Então, onde
Data->Link->Link == NULL
está o ponto final, dandoData->Link
como ponto de fusão (no final da lista).EDITAR:
Ok, a partir da imagem que você postou, você analisa as duas listas, a menor primeiro. Com a menor lista, você pode manter as referências ao nó a seguir. Agora, quando você analisa a segunda lista, faz uma comparação na referência para descobrir onde Referência [i] é a referência em LinkedList [i] -> Link. Isso dará o ponto de fusão. Hora de explicar com fotos (sobrepor os valores na foto do OP).
Você tem uma lista vinculada (referências mostradas abaixo):
A->B->C->D->E
Você tem uma segunda lista vinculada:
1->2->
Com a lista mesclada, as referências seriam as seguintes:
1->2->D->E->
Portanto, você mapeia a primeira lista "menor" (como a lista mesclada, que é o que estamos contando, tem um comprimento de 4 e a lista principal 5)
Faça um loop pela primeira lista, mantenha uma referência de referências.
A lista conterá as seguintes referências
Pointers { 1, 2, D, E }
.Vamos agora para a segunda lista:
Claro, você mantém uma nova lista de indicadores, mas isso não está fora das especificações. No entanto, a primeira lista é analisada exatamente uma vez, e a segunda lista só será totalmente analisada se não houver ponto de fusão. Caso contrário, ele terminará mais cedo (no ponto de fusão).
fonte
Eu testei um caso de mesclagem no meu FC9 x86_64 e imprimo cada endereço de nó conforme mostrado abaixo:
Note que eu havia alinhado a estrutura do nó, então quando malloc () um nó, o endereço é alinhado com 16 bytes, veja pelo menos 4 bits. Os bits mínimos são 0s, ou seja, 0x0 ou 000b. Portanto, se você estiver no mesmo caso especial (endereço de nó alinhado) também, você pode usar pelo menos 4 bits. Por exemplo, ao viajar ambas as listas de ponta a ponta, defina 1 ou 2 dos 4 bits do endereço do nó visitante, ou seja, defina um sinalizador;
Observe que os sinalizadores acima não afetarão o endereço do nó real, mas apenas o valor do ponteiro do nó SALVO.
Uma vez encontrado, alguém definiu o (s) bit (s) de sinalizador (es), o primeiro nó encontrado deve ser o ponto de fusão. depois de fazer isso, você restauraria o endereço do nó limpando os bits de sinalização que você definiu. enquanto uma coisa importante é que você deve ter cuidado ao iterar (por exemplo, node = node-> next) para fazer a limpeza. lembre-se de que você configurou bits de sinalização, então faça desta forma
Como essa proposta irá restaurar os endereços de nó modificados, ela pode ser considerada como "sem modificação".
fonte
Pode haver uma solução simples, mas exigirá um espaço auxiliar. A ideia é percorrer uma lista e armazenar cada endereço em um mapa hash, agora percorrer a outra lista e comparar se o endereço está no mapa hash ou não. Cada lista é percorrida apenas uma vez. Não há modificação em nenhuma lista. O comprimento ainda é desconhecido. Espaço auxiliar usado: O (n) onde 'n' é o comprimento da primeira lista percorrida.
fonte
esta solução itera cada lista apenas uma vez ... nenhuma modificação da lista também é necessária ... embora você possa reclamar de espaço ..
1) Basicamente, você itera na lista1 e armazena o endereço de cada nó em uma matriz (que armazena o valor int não assinado)
2) Em seguida, você itera a lista2, e para o endereço de cada nó ---> você pesquisa através do array que encontrou uma correspondência ou não ... se o fizer, então este é o nó de fusão
Espero que seja uma solução válida ...
fonte
Não há necessidade de modificar nenhuma lista. Existe uma solução em que só temos que percorrer cada lista uma vez.
fonte
fonte
Aqui está uma solução ingênua, não é necessário percorrer listas inteiras.
se o seu nó estruturado tem três campos como
digamos que você tenha duas cabeças (cabeça1 e cabeça2) apontando para a cabeça de duas listas.
Percorra a lista no mesmo ritmo e coloque o sinalizador = 1 (sinalizador visitado) para esse nó,
fonte
Que tal agora:
Se você só tem permissão para percorrer cada lista apenas uma vez, pode criar um novo nó, percorrer a primeira lista para que cada nó aponte para este novo nó e percorrer a segunda lista para ver se algum nó está apontando para seu novo nó ( esse é o seu ponto de fusão). Se a segunda travessia não levar ao seu novo nó, as listas originais não têm um ponto de fusão.
Se você tiver permissão para percorrer as listas mais de uma vez, poderá percorrer cada lista para encontrar nossos comprimentos e, se forem diferentes, omita os nós "extras" no início da lista mais longa. Em seguida, basta percorrer as duas listas, uma etapa de cada vez, e encontrar o primeiro nó de fusão.
fonte
Etapas em Java:
fonte
Podemos resolvê-lo com eficiência introduzindo o campo "isVisited". Percorra a primeira lista e defina o valor "isVisited" como "true" para todos os nós até o final. Agora comece a partir do segundo e encontre o primeiro nó onde flag é verdadeiro e Boom, seu ponto de fusão.
fonte
Etapa 1: encontre o comprimento de ambas as listas Etapa 2: Encontre a diferença e mova a maior lista com a diferença Etapa 3: Agora as duas listas estarão em posições semelhantes. Etapa 4: percorrer a lista para encontrar o ponto de fusão
fonte
fonte
Use o mapa ou o dicionário para armazenar o endereço e o valor do nó. se o endereço já existe no Mapa / Dicionário, o valor da chave é a resposta. Eu fiz isso:
fonte
Solução de complexidade AO (n). Mas com base em uma suposição.
a suposição é: ambos os nós têm apenas inteiros positivos.
lógica: torne todos os inteiros da lista1 negativos. Em seguida, percorra a lista2, até obter um número inteiro negativo. Uma vez encontrado => pegue, mude o sinal de volta para positivo e retorne.
fonte
Podemos usar dois ponteiros e mover-nos de tal forma que se um dos ponteiros for nulo o apontamos para o cabeçalho da outra lista e o mesmo para o outro, desta forma se os comprimentos da lista forem diferentes eles se encontrarão na segunda passagem . Se o comprimento da lista1 for ne lista2 for m, sua diferença será d = abs (nm). Eles cobrirão essa distância e se encontrarão no ponto de fusão.
Código:
fonte
Você pode adicionar os nós de
list1
a um hashset e o loop através do segundo e se algum nó delist2
já estiver presente no conjunto. Se sim, então esse é o nó de mesclagemfonte
Solução usando javascript
fonte
Se a edição da lista vinculada for permitida,
fonte