Check if two linked lists merge. If so, where?

AlgorithmLinked ListData Structures

Algorithm Problem Overview


This question may be old, but I couldn't think of an answer.

Say, there are two lists of different lengths, merging at a point; how do we know where the merging point is?

Conditions:

  1. We don't know the length
  2. We should parse each list only once.

Example of two merged linked lists.

Algorithm Solutions


Solution 1 - Algorithm

The following is by far the greatest of all I have seen - O(N), no counters. I got it during an interview to a candidate S.N. at VisionMap.

Make an interating pointer like this: it goes forward every time till the end, and then jumps to the beginning of the opposite list, and so on. Create two of these, pointing to two heads. Advance each of the pointers by 1 every time, until they meet. This will happen after either one or two passes.

I still use this question in the interviews - but to see how long it takes someone to understand why this solution works.

Solution 2 - Algorithm

Pavel's answer requires modification of the lists as well as iterating each list twice.

Here's a solution that only requires iterating each list twice (the first time to calculate their length; if the length is given you only need to iterate once).

The idea is to ignore the starting entries of the longer list (merge point can't be there), so that the two pointers are an equal distance from the end of the list. Then move them forwards until they merge.

lenA = count(listA) //iterates list A
lenB = count(listB) //iterates list B

ptrA = listA
ptrB = listB

//now we adjust either ptrA or ptrB so that they are equally far from the end
while(lenA > lenB):
    ptrA = ptrA->next
    lenA--
while(lenB > lenA):
    prtB = ptrB->next
    lenB--

while(ptrA != NULL):
    if (ptrA == ptrB):
        return ptrA //found merge point
    ptrA = ptrA->next
    ptrB = ptrB->next

This is asymptotically the same (linear time) as my other answer but probably has smaller constants, so is probably faster. But I think my other answer is cooler.

Solution 3 - Algorithm

If

  • by "modification is not allowed" it was meant "you may change but in the end they should be restored", and
  • we could iterate the lists exactly twice

the following algorithm would be the solution.

First, the numbers. Assume the first list is of length a+c and the second one is of length b+c, where c is the length of their common "tail" (after the mergepoint). Let's denote them as follows:

x = a+c
y = b+c

Since we don't know the length, we will calculate x and y without additional iterations; you'll see how.

Then, we iterate each list and reverse them while iterating! If both iterators reach the merge point at the same time, then we find it out by mere comparing. Otherwise, one pointer will reach the merge point before the other one.

After that, when the other iterator reaches the merge point, it won't proceed to the common tail. Instead will go back to the former beginning of the list that had reached merge-point before! So, before it reaches the end of the changed list (i.e. the former beginning of the other list), he will make a+b+1 iterations total. Let's call it z+1.

The pointer that reached the merge-point first, will keep iterating, until reaches the end of the list. The number of iterations it made should be calculated and is equal to x.

Then, this pointer iterates back and reverses the lists again. But now it won't go back to the beginning of the list it originally started from! Instead, it will go to the beginning of the other list! The number of iterations it made should be calculated and equal to y.

So we know the following numbers:

x = a+c
y = b+c
z = a+b

From which we determine that

a = (+x-y+z)/2
b = (-x+y+z)/2
c = (+x+y-z)/2

Which solves the problem.

Solution 4 - Algorithm

Well, if you know that they will merge:

Say you start with:

A-->B-->C
        |
        V
1-->2-->3-->4-->5
  1. Go through the first list setting each next pointer to NULL.

Now you have:

A   B   C
        
1-->2-->3   4   5

2) Now go through the second list and wait until you see a NULL, that is your merge point.

If you can't be sure that they merge you can use a sentinel value for the pointer value, but that isn't as elegant.

Solution 5 - Algorithm

If we could iterate lists exactly twice, than I can provide method for determining merge point:

  • iterate both lists and calculate lengths A and B
  • calculate difference of lengths C = |A-B|;
  • start iterating both list simultaneously, but make additional C steps on list which was greater
  • this two pointers will meet each other in the merging point

Solution 6 - Algorithm

Here's a solution, computationally quick (iterates each list once) but uses a lot of memory:

for each item in list a
  push pointer to item onto stack_a

for each item in list b
  push pointer to item onto stack_b

while (stack_a top == stack_b top) // where top is the item to be popped next
  pop stack_a
  pop stack_b

// values at the top of each stack are the items prior to the merged item

Solution 7 - Algorithm

You can use a set of Nodes. Iterate through one list and add each Node to the set. Then iterate through the second list and for every iteration, check if the Node exists in the set. If it does, you've found your merge point :)

Solution 8 - Algorithm

This arguably violates the "parse each list only once" condition, but implement the tortoise and hare algorithm (used to find the merge point and cycle length of a cyclic list) so you start at List A, and when you reach the NULL at the end you pretend it's a pointer to the beginning of list B, thus creating the appearance of a cyclic list. The algorithm will then tell you exactly how far down List A the merge is (the variable 'mu' according to the Wikipedia description).

Also, the "lambda" value tells you the length of list B, and if you want, you can work out the length of list A during the algorithm (when you redirect the NULL link).

Solution 9 - Algorithm

Maybe I am over simplifying this, but simply iterate the smallest list and use the last nodes Link as the merging point?

So, where Data->Link->Link == NULL is the end point, giving Data->Link as the merging point (at the end of the list).

EDIT:

Okay, from the picture you posted, you parse the two lists, the smallest first. With the smallest list you can maintain the references to the following node. Now, when you parse the second list you do a comparison on the reference to find where Reference [i] is the reference at LinkedList[i]->Link. This will give the merge point. Time to explain with pictures (superimpose the values on the picture the OP).

You have a linked list (references shown below):

A->B->C->D->E

You have a second linked list:

1->2->

With the merged list, the references would then go as follows:

1->2->D->E->

Therefore, you map the first "smaller" list (as the merged list, which is what we are counting has a length of 4 and the main list 5)

Loop through the first list, maintain a reference of references.

The list will contain the following references Pointers { 1, 2, D, E }.

We now go through the second list:

-> A - Contains reference in Pointers? No, move on
-> B - Contains reference in Pointers? No, move on
-> C - Contains reference in Pointers? No, move on
-> D - Contains reference in Pointers? Yes, merge point found, break.

Sure, you maintain a new list of pointers, but thats not outside the specification. However the first list is parsed exactly once, and the second list will only be fully parsed if there is no merge point. Otherwise, it will end sooner (at the merge point).

Solution 10 - Algorithm

I have tested a merge case on my FC9 x86_64, and print every node address as shown below:

Head A 0x7fffb2f3c4b0
0x214f010
0x214f030
0x214f050
0x214f070
0x214f090
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170


Head B 0x7fffb2f3c4a0
0x214f0b0
0x214f0d0
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170

Note becase I had aligned the node structure, so when malloc() a node, the address is aligned w/ 16 bytes, see the least 4 bits. The least bits are 0s, i.e., 0x0 or 000b. So if your are in the same special case (aligned node address) too, you can use these least 4 bits. For example when travel both lists from head to tail, set 1 or 2 of the 4 bits of the visiting node address, that is, set a flag;

next_node = node->next;
node = (struct node*)((unsigned long)node | 0x1UL);

Note above flags won't affect the real node address but only your SAVED node pointer value.

Once found somebody had set the flag bit(s), then the first found node should be the merge point. after done, you'd restore the node address by clear the flag bits you had set. while an important thing is that you should be careful when iterate (e.g. node = node->next) to do clean. remember you had set flag bits, so do this way

real_node = (struct node*)((unsigned long)node) & ~0x1UL);
real_node = real_node->next;
node = real_node;
 

Because this proposal will restore the modified node addresses, it could be considered as "no modification".

Solution 11 - Algorithm

There can be a simple solution but will require an auxilary space. The idea is to traverse a list and store each address in a hash map, now traverse the other list and match if the address lies in the hash map or not. Each list is traversed only once. There's no modification to any list. Length is still unknown. Auxiliary space used: O(n) where 'n' is the length of first list traversed.

Solution 12 - Algorithm

this solution iterates each list only once...no modification of list required too..though you may complain about space..

  1. Basically you iterate in list1 and store the address of each node in an array(which stores unsigned int value)

  2. Then you iterate list2, and for each node's address ---> you search through the array that you find a match or not...if you do then this is the merging node

    //pseudocode //for the first list p1=list1; unsigned int addr[];//to store addresses i=0; while(p1!=null){ addr[i]=&p1; p1=p1->next; } int len=sizeof(addr)/sizeof(int);//calculates length of array addr //for the second list p2=list2; while(p2!=null){ if(search(addr[],len,&p2)==1)//match found { //this is the merging node return (p2); } p2=p2->next; }

    int search(addr,len,p2){ i=0;
    while(i

Hope it is a valid solution...

Solution 13 - Algorithm

There is no need to modify any list. There is a solution in which we only have to traverse each list once.

  1. Create two stacks, lets say stck1 and stck2.
  2. Traverse 1st list and push a copy of each node you traverse in stck1.
  3. Same as step two but this time traverse 2nd list and push the copy of nodes in stck2.
  4. Now, pop from both stacks and check whether the two nodes are equal, if yes then keep a reference to them. If no, then previous nodes which were equal are actually the merge point we were looking for.

Solution 14 - Algorithm

int FindMergeNode(Node headA, Node headB) {
  Node currentA = headA;
  Node currentB = headB;

  // Do till the two nodes are the same
  while (currentA != currentB) {
    // If you reached the end of one list start at the beginning of the other
    // one currentA
    if (currentA.next == null) {
      currentA = headA;
    } else {
      currentA = currentA.next;
    }
    // currentB
    if (currentB.next == null) {
      currentB = headB;
    } else {
      currentB = currentB.next;
    }
  }
  return currentB.data;
}

Solution 15 - Algorithm

We can use two pointers and move in a fashion such that if one of the pointers is null we point it to the head of the other list and same for the other, this way if the list lengths are different they will meet in the second pass. If length of list1 is n and list2 is m, their difference is d=abs(n-m). They will cover this distance and meet at the merge point.
Code:

int findMergeNode(SinglyLinkedListNode* head1, SinglyLinkedListNode* head2) {
    SinglyLinkedListNode* start1=head1;
    SinglyLinkedListNode* start2=head2;
    while (start1!=start2){
        start1=start1->next;
        start2=start2->next;
        if (!start1)
        start1=head2;
        if (!start2)
        start2=head1;
    }
    return start1->data;
}

Solution 16 - Algorithm

Here is naive solution , No neeed to traverse whole lists.

if your structured node has three fields like

struct node {
    int data;   
    int flag;  //initially set the flag to zero  for all nodes
    struct node *next;
};

say you have two heads (head1 and head2) pointing to head of two lists.

Traverse both the list at same pace and put the flag =1(visited flag) for that node ,

  if (node->next->field==1)//possibly longer list will have this opportunity
      //this will be your required node. 
      

Solution 17 - Algorithm

How about this:

  1. If you are only allowed to traverse each list only once, you can create a new node, traverse the first list to have every node point to this new node, and traverse the second list to see if any node is pointing to your new node (that's your merge point). If the second traversal doesn't lead to your new node then the original lists don't have a merge point.

  2. If you are allowed to traverse the lists more than once, then you can traverse each list to find our their lengths and if they are different, omit the "extra" nodes at the beginning of the longer list. Then just traverse both lists one step at a time and find the first merging node.

Solution 18 - Algorithm

Steps in Java:

  1. Create a map.
  2. Start traversing in the both branches of list and Put all traversed nodes of list into the Map using some unique thing related to Nodes(say node Id) as Key and put Values as 1 in the starting for all.
  3. When ever first duplicate key comes, increment the value for that Key (let say now its value became 2 which is > 1.
  4. Get the Key where the value is greater than 1 and that should be the node where two lists are merging.

Solution 19 - Algorithm

We can efficiently solve it by introducing "isVisited" field. Traverse first list and set "isVisited" value to "true" for all nodes till end. Now start from second and find first node where flag is true and Boom ,its your merging point.

Solution 20 - Algorithm

Step 1: find lenght of both the list Step 2 : Find the diff and move the biggest list with the difference Step 3 : Now both list will be in similar position. Step 4 : Iterate through list to find the merge point

//Psuedocode
def findmergepoint(list1, list2):
lendiff = list1.length() > list2.length() : list1.length() - list2.length() ? list2.lenght()-list1.lenght()
biggerlist = list1.length() > list2.length() : list1 ? list2  # list with biggest length
smallerlist = list1.length() < list2.length() : list2 ? list1 # list with smallest length


# move the biggest length to the diff position to level both the list at the same position
for i in range(0,lendiff-1):
	biggerlist = biggerlist.next
#Looped only once.	
while ( biggerlist is not None and smallerlist is not None ):
	if biggerlist == smallerlist :
		return biggerlist #point of intersection


return None // No intersection found

Solution 21 - Algorithm

int FindMergeNode(Node *headA, Node *headB)
{
    Node *tempB=new Node;
    tempB=headB;
   while(headA->next!=NULL)
       {
       while(tempB->next!=NULL)
           {
           if(tempB==headA)
               return tempB->data;
           tempB=tempB->next;
       }
       headA=headA->next;
       tempB=headB;
   }
    return headA->data;
}

Solution 22 - Algorithm

Use Map or Dictionary to store the addressess vs value of node. if the address alread exists in the Map/Dictionary then the value of the key is the answer. I did this:

int FindMergeNode(Node headA, Node headB) {

Map<Object, Integer> map = new HashMap<Object, Integer>();

while(headA != null || headB != null)
{
    if(headA != null && map.containsKey(headA.next))
    {
        return map.get(headA.next);
    }

    if(headA != null && headA.next != null)
    {
         map.put(headA.next, headA.next.data);
         headA = headA.next;
    }

    if(headB != null && map.containsKey(headB.next))
    {
        return map.get(headB.next);
    }

    if(headB != null && headB.next != null)
    {
        map.put(headB.next, headB.next.data);
        headB = headB.next;
    }
}

return 0;
}

Solution 23 - Algorithm

A O(n) complexity solution. But based on an assumption.

assumption is: both nodes are having only positive integers.

logic : make all the integer of list1 to negative. Then walk through the list2, till you get a negative integer. Once found => take it, change the sign back to positive and return.

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
    
    SinglyLinkedListNode current = head1; //head1 is give to be not null.
    
    //mark all head1 nodes as negative
    while(true){
        current.data = -current.data;
        current = current.next;
        if(current==null) break;
    }
    
    current=head2; //given as not null
    while(true){
        if(current.data<0) return -current.data;
        current = current.next;
    }

}

Solution 24 - Algorithm

You can add the nodes of list1 to a hashset and the loop through the second and if any node of list2 is already present in the set .If yes, then thats the merge node

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
    HashSet<SinglyLinkedListNode> set=new HashSet<SinglyLinkedListNode>();
    while(head1!=null)
    {
        set.add(head1);
        head1=head1.next;
    }
    while(head2!=null){
        if(set.contains(head2){
            return head2.data;
        }
    }
    return -1;
}

Solution 25 - Algorithm

Solution using javascript

var getIntersectionNode = function(headA, headB) {
    
    if(headA == null || headB == null) return null;
    
    let countA = listCount(headA);
    let countB = listCount(headB);
    
    let diff = 0;
    if(countA > countB) {

        diff = countA - countB;
        for(let i = 0; i < diff; i++) {
            headA = headA.next;
        }
    } else if(countA < countB) {
        diff = countB - countA;
        for(let i = 0; i < diff; i++) {
            headB = headB.next;
        }
    }

    return getIntersectValue(headA, headB);
};

function listCount(head) {
    let count = 0;
    while(head) {
        count++;
        head = head.next;
    }
    return count;
}

function getIntersectValue(headA, headB) {
    while(headA && headB) {
        if(headA === headB) {
            return headA;
        }
        headA = headA.next;
        headB = headB.next;
    }
    return null;
}

Solution 26 - Algorithm

If editing the linked list is allowed,

  1. Then just make the next node pointers of all the nodes of list 2 as null.
  2. Find the data value of the last node of the list 1. This will give you the intersecting node in single traversal of both the lists, with "no hi fi logic".

Solution 27 - Algorithm

Follow the simple logic to solve this problem: Since both pointer A and B are traveling with same speed. To meet both at the same point they must be cover the same distance. and we can achieve this by adding the length of a list to another.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrplusgView Question on Stackoverflow
Solution 1 - AlgorithmPavel RadzivilovskyView Answer on Stackoverflow
Solution 2 - AlgorithmArteliusView Answer on Stackoverflow
Solution 3 - AlgorithmP ShvedView Answer on Stackoverflow
Solution 4 - AlgorithmtsterView Answer on Stackoverflow
Solution 5 - AlgorithmrachvelaView Answer on Stackoverflow
Solution 6 - AlgorithmSkizzView Answer on Stackoverflow
Solution 7 - AlgorithmisyiView Answer on Stackoverflow
Solution 8 - AlgorithmArteliusView Answer on Stackoverflow
Solution 9 - AlgorithmKyle RosendoView Answer on Stackoverflow
Solution 10 - AlgorithmTestView Answer on Stackoverflow
Solution 11 - AlgorithmVikas AgarwalView Answer on Stackoverflow
Solution 12 - Algorithmrajya vardhanView Answer on Stackoverflow
Solution 13 - AlgorithmABVashView Answer on Stackoverflow
Solution 14 - AlgorithmFahad IsrarView Answer on Stackoverflow
Solution 15 - Algorithmaditya singhView Answer on Stackoverflow
Solution 16 - AlgorithmAnil AryaView Answer on Stackoverflow
Solution 17 - Algorithmuser2024069View Answer on Stackoverflow
Solution 18 - AlgorithmKing KBView Answer on Stackoverflow
Solution 19 - AlgorithmRiya kathilView Answer on Stackoverflow
Solution 20 - AlgorithmsvaithinView Answer on Stackoverflow
Solution 21 - AlgorithmYachana YachanaView Answer on Stackoverflow
Solution 22 - AlgorithmVishal AnandView Answer on Stackoverflow
Solution 23 - Algorithmuser3828943View Answer on Stackoverflow
Solution 24 - AlgorithmC.B. ShivanandaView Answer on Stackoverflow
Solution 25 - AlgorithmRama AdaikkalamView Answer on Stackoverflow
Solution 26 - AlgorithmDevvrat JoshiView Answer on Stackoverflow
Solution 27 - AlgorithmUday KumarView Answer on Stackoverflow