Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.
we have l1:
ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 4, next: None}}}
and l2:
ListNode{val: 1, next: ListNode{val: 3, next: ListNode{val: 4, next: None}}}
I merge them using the following code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
print(l1)
print(l2)
out = ListNode(-1)
temp = out
while l1 and l2:
if (l1.val < l2.val):
temp.next = l1
l1 = l1.next
else:
temp.next = l2
l2 = l2.next
temp = temp.next
print(out)
This is what out is:
ListNode{val: -1, next: ListNode{val: 1, next: ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 3, next: ListNode{val: 4, next: None}}}}}}
My question is how is out getting updated?
CodePudding user response:
out gets mutated in the first iteration of the while loop.
It may help to visualise it.
Just before the loop starts, we have created a dummy node (with value -1) and referred to it with out and temp:
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
│ next: ────────> │ next: ────────> │ next: None │
out └────────────┘ └────────────┘ └────────────┘
↓
┌────────────┐
│ data: -1 │
│ next: None │
└────────────┘
↑
temp ┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 3 │ │ data: 4 │
│ next: ────────> │ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑
l2
In the first iteration we get into the else block, where temp is mutated. Since temp and out reference the same object, this mutates out.
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
│ next: ────────> │ next: ────────> │ next: None │
out └────────────┘ └────────────┘ └────────────┘
↓
┌────────────┐
│ data: -1 │
│ next: ──────┐
└────────────┘│
↑ │
temp │ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ │ data: 1 │ │ data: 3 │ │ data: 4 │
└> │ next: ────────> │ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑
l2
After this update, both l2 and temp are "moved" to refer to their successor. This ends the first iteration:
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
│ next: ────────> │ next: ────────> │ next: None │
out └────────────┘ └────────────┘ └────────────┘
↓
┌────────────┐
│ data: -1 │
│ next: ──────┐
└────────────┘│
│
│ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ │ data: 1 │ │ data: 3 │ │ data: 4 │
└> │ next: ────────> │ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑ ↑
temp l2
We don't really have to continue through the algorithm, as from now on out will not be mutated again: that job has been done. But let's just continue with one more iteration (the second iteration). There we get into the if block, and temp gets mutated again (but this time, it is not a synonym for out):
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
┌> │ next: ────────> │ next: ────────> │ next: None │
out │ └────────────┘ └────────────┘ └────────────┘
↓ └────────────────┐
┌────────────┐ │
│ data: -1 │ │
│ next: ──────┐ │
└────────────┘│ │
│ │
│ ┌────────────┐│ ┌────────────┐ ┌────────────┐
│ │ data: 1 ││ │ data: 3 │ │ data: 4 │
└> │ next: ──────┘ │ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑ ↑
temp l2
...and both l1 and temp move to their successors:
temp l1
↓ ↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
┌> │ next: ────────> │ next: ────────> │ next: None │
out │ └────────────┘ └────────────┘ └────────────┘
↓ └────────────────┐
┌────────────┐ │
│ data: -1 │ │
│ next: ──────┐ │
└────────────┘│ │
│ │
│ ┌────────────┐│ ┌────────────┐ ┌────────────┐
│ │ data: 1 ││ │ data: 3 │ │ data: 4 │
└> │ next: ──────┘ │ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑
l2
Continuing like that, temp will remain the tail of the resulting list that is being wired. After the last iteration, we will have this:
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
┌> │ next: ────────> │ next: ──────┐ │ next: None │
out │ └────────────┘ └────────────┘│ └────────────┘
↓ └────────────────┐ ┌───────────────┘
┌────────────┐ │ │
│ data: -1 │ │ │
│ next: ──────┐ │ │
└────────────┘│ │ │
│ │ │
│ ┌────────────┐│ │ ┌────────────┐ ┌────────────┐
│ │ data: 1 ││ │ │ data: 3 │ │ data: 4 │
└> │ next: ──────┘ └>│ next: ────────> │ next: None │
└────────────┘ └────────────┘ └────────────┘
↑
temp
The job is not entirely done, as some code is missing from the snippet you have posted. When the while loop exits, one of l1 or l2 will not be None, and that represents a part that still needs to be appended to the resulting list. As temp refers to the current tail of the resulting list, we should set its next reference to either l1 or l2 -- whichever is not None.
So the code should have something like the following statement after the loop:
temp.next = l1 or l2
...which results in:
l1
↓
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
┌> │ next: ────────> │ next: ──────┐ ┌>│ next: None │
out │ └────────────┘ └────────────┘│ │ └────────────┘
↓ └────────────────┐ ┌───────────────┘ └───────────────┐
┌────────────┐ │ │ │
│ data: -1 │ │ │ │
│ next: ──────┐ │ │ │
└────────────┘│ │ │ │
│ │ │ │
│ ┌────────────┐│ │ ┌────────────┐ ┌────────────┐│
│ │ data: 1 ││ │ │ data: 3 │ │ data: 4 ││
└> │ next: ──────┘ └>│ next: ────────> │ next: ──────┘
└────────────┘ └────────────┘ └────────────┘
↑
temp
And finally, the function should return the result. As out refers to a dummy node, we should not just return out, but out.next:
return out.next
The returned list reference will be to this:
┌────────────┐ ┌────────────┐ ┌────────────┐
│ data: 1 │ │ data: 2 │ │ data: 4 │
┌> │ next: ────────> │ next: ──────┐ ┌>│ next: None │
│ └────────────┘ └────────────┘│ │ └────────────┘
└────────────────┐ ┌───────────────┘ └───────────────┐
│ │ │
┌────────────┐│ │ ┌────────────┐ ┌────────────┐│
│ data: 1 ││ │ │ data: 3 │ │ data: 4 ││
returned → │ next: ──────┘ └>│ next: ────────> │ next: ──────┘
└────────────┘ └────────────┘ └────────────┘
I hope this clarifies it.
CodePudding user response:
If it helps, you don't even need any temporary nodes. You can relink the existing nodes which makes it much simpler:
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not (l1 and l2):
return l1 or l2
if l2.val < l1.val:
l1, l2 = l2, l1
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
