21. Merge Two Sorted Lists
- Паттерн:
- two pointers + dummy node
- Уақыт:
- O(n + m)
- Жад:
- O(1)
- Жазылды:
Талдаулар ағылшын тілінде жазылған.
Есеп
Тәсіл
dummy) to hold onto, since the chain doesn't exist yet.
current is your hand — starts on the paperclip, and after every attachment, slides forward onto whatever you just attached. If your hand never moves, you keep re-clipping new links onto the paperclip instead of onto the end of the growing chain, and everything before your hand becomes unreachable.
dummy -> 1 -> 1 -> 2 -> 3 -> 4 -> 4
↑ ↑
(never moves) current ends up hereШешім
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode();
ListNode current = dummy;
while (list1 != null && list2 != null) {
if (list1.val < list2.val) {
current.next = list1;
list1 = list1.next;
} else {
current.next = list2;
list2 = list2.next;
}
current = current.next; // the line I kept forgetting
}
// whichever list still has leftovers just gets attached wholesale
if (list1 != null) {
current.next = list1;
}
if (list2 != null) {
current.next = list2;
}
return dummy.next; // NOT dummy, NOT current — the real head is right after dummy
}Қателер
First I tried checking list1.val != null— forgotvalis anint, and primitives can never benull. Should have been checkinglist1 != null(the node reference itself), not the value inside it.Then I tried if (list1 && !list2)— treating aListNodereference like a boolean, which isn't a thing in Java (no truthy/falsy checks like JS or Python).Even after fixing the null checks, I only had one pointer ( current) doing the job of two things: (a) remembering where the merged list starts, and (b) tracking where to attach the next node. Those need to be two separate variables —dummy(never moves) andcurrent(moves every iteration).Even after splitting those into two variables, I forgot the actual moving part: current = current.next. I attached nodes fine, but never movedcurrentforward, so every new attachment silently overwrote the previous one and orphaned it in memory.
The bug, traced by hand
list1 = [1, 2, 4], list2 = [1, 3, 4]. Without current = current.next:
Iteration 1: 1 < 1false →dummy.next = list2's "1" node.currentstill =dummy.Iteration 2: 1 < 3true →dummy.next = list1's "1" node. The node from iteration 1 is now unreachable — nothing points to it anymore. Same root idea as thex = x++gotcha from OCA: writing to the same slot twice instead of advancing.
current moves onto the newly attached node each time, so the next attachment writes to current.next — which is a fresh, unused slot — instead of overwriting the same one repeatedly.
Түйін
Three lines per attachment, not two
current.next = <chosen node>— attach it<sourceList> = <sourceList>.next— advance the list you took the node fromcurrent = current.next— advance your own "where do I attach next" pointer
Why return dummy.next and not dummy or current
return dummy.next and not dummy or currentdummy— the paperclip itself, never a real part of the list. Returning it would hand back a list with a bogus0value glued to the front.current— by the time the loop ends, this is sitting at the last node attached, not the first. Returning it would only give back the tail end.dummy.next— the paperclip's.nextfield was set exactly once, on the very first attachment, and never touched again after that (onlycurrentkept moving). Sodummy.nextreliably points at the true head.
Java 8
while loop, and object creation. Nothing version-specific.
Уақыт пен жад
Time: O(n + m) — walk each list once, total. Space: O(1) — only a few reference variables, no new list built from scratch.
Өзімді тексеру
Can I explain, without looking, why currentneeds to move butdummynever does?What breaks if I return currentinstead ofdummy.next?What breaks if I forget the leftover-list handling after the loop — walk through an example where list1empties out early withlist2still having 3 nodes left.Try writing the recursive version and figure out why it doesn't need a dummy node at all (this connects to the same question I skipped on LC 206).