11"""
2- LeetCode 21. Merge Two Sorted Lists
2+ =========================================================
3+ 21. Merge Two Sorted Lists
4+ LeetCode: https://leetcode.com/problems/merge-two-sorted-lists/
35
4- Problem:
5- You are given the heads of two sorted linked lists, list1 and list2.
6+ Approach 1: Brute Force (Create New List)
7+ Approach 2: Optimal (Iterative In-Place)
68
7- Merge the two lists into one sorted linked list and return the head
8- of the merged list.
9+ Author: Your Name
10+ =========================================================
11+
12+ Problem Statement
13+ -----------------
14+ You are given the heads of two sorted linked lists.
15+
16+ Merge the two lists into one sorted linked list by splicing together
17+ the nodes of the first two lists.
18+
19+ Return the head of the merged linked list.
920
1021Example:
1122Input:
12- list1 = 1 -> 2 -> 4
13- list2 = 1 -> 3 -> 4
23+ List1 = [1,2,4]
24+ List2 = [1,3,4]
1425
1526Output:
16- 1 -> 1 -> 2 -> 3 -> 4 -> 4
27+ [1,1,2,3,4,4]
28+ """
29+
30+
31+ # =========================================================
32+ # Definition for singly-linked list.
33+ # =========================================================
34+ # class ListNode:
35+ # def __init__(self, val=0, next=None):
36+ # self.val = val
37+ # self.next = next
1738
18- ---------------------------------------------------------
19- Approach: Recursive
20- ---------------------------------------------------------
2139
22- Idea:
23- Since both linked lists are already sorted, compare the current
24- nodes of both lists.
40+ # =========================================================
41+ # APPROACH 1 : BRUTE FORCE (Create a New Linked List)
42+ # =========================================================
43+ """
44+ Algorithm
45+ ---------
46+ 1. Create a dummy node.
47+ 2. Traverse both linked lists simultaneously.
48+ 3. Compare current nodes.
49+ 4. Create a new node with the smaller value and attach it.
50+ 5. Move the corresponding pointer.
51+ 6. After one list ends, copy the remaining nodes of the other list.
52+ 7. Return dummy.next.
53+
54+ Time Complexity:
55+ O(m + n)
56+
57+ Space Complexity:
58+ O(m + n)
59+ (New nodes are created.)
60+ """
2561
26- 1. If list1's value is smaller (or equal), choose list1's node.
27- 2. Recursively merge the remaining nodes of list1 with list2.
28- 3. If list2's value is smaller, choose list2's node.
29- 4. Recursively merge list1 with the remaining nodes of list2.
30- 5. Continue until one list becomes empty.
3162
32- Base Cases:
33- - If list1 is empty, return list2.
34- - If list2 is empty, return list1.
63+ class Solution :
64+ def mergeTwoLists (self , head1 : Optional [ListNode ], head2 : Optional [ListNode ]) -> Optional [ListNode ]:
3565
36- Why it works:
37- At every recursive call, the smallest available node is placed
38- into the merged list, maintaining sorted order.
66+ dummy = ListNode (0 )
67+ tail = dummy
3968
40- ---------------------------------------------------------
41- Dry Run
42- ---------------------------------------------------------
69+ while head1 and head2 :
4370
44- list1 = 1 -> 2 -> 4
45- list2 = 1 -> 3 -> 4
71+ if head1 .val <= head2 .val :
72+ tail .next = ListNode (head1 .val )
73+ head1 = head1 .next
74+ else :
75+ tail .next = ListNode (head2 .val )
76+ head2 = head2 .next
4677
47- Compare:
48- 1 <= 1
78+ tail = tail .next
4979
50- Choose first 1
80+ while head1 :
81+ tail .next = ListNode (head1 .val )
82+ head1 = head1 .next
83+ tail = tail .next
5184
52- 1 -> merge(2->4, 1->3->4)
85+ while head2 :
86+ tail .next = ListNode (head2 .val )
87+ head2 = head2 .next
88+ tail = tail .next
5389
54- Compare:
55- 2 > 1
90+ return dummy .next
5691
57- Choose second 1
5892
59- 1 -> merge(2->4, 3->4)
93+ # =========================================================
94+ # APPROACH 2 : OPTIMAL (Iterative In-Place)
95+ # =========================================================
96+ """
97+ Algorithm
98+ ---------
99+ 1. Create a dummy node.
100+ 2. Maintain a tail pointer.
101+ 3. Compare the current nodes of both lists.
102+ 4. Attach the smaller node directly to tail.
103+ 5. Move the corresponding list pointer.
104+ 6. Move tail forward.
105+ 7. Once one list becomes empty, attach the remaining list.
106+ 8. Return dummy.next.
60107
61- Compare:
62- 2 <= 3
108+ Example
109+ -------
110+ List1 : 1 -> 2 -> 4
111+ List2 : 1 -> 3 -> 4
63112
64- Choose 2
113+ dummy
65114
66- 2 -> merge(4, 3->4)
115+ Step 1:
116+ dummy -> 1
117+ tail -> 1
67118
68- Compare :
69- 4 > 3
119+ Step 2 :
120+ dummy -> 1 -> 1
70121
71- Choose 3
122+ Step 3:
123+ dummy -> 1 -> 1 -> 2
72124
73- 3 -> merge(4, 4)
125+ Step 4:
126+ dummy -> 1 -> 1 -> 2 -> 3
74127
75- Compare :
76- 4 <= 4
128+ Step 5 :
129+ dummy -> 1 -> 1 -> 2 -> 3 -> 4
77130
78- Choose first 4
131+ Attach remaining node:
79132
80- 4 -> merge(None, 4)
133+ dummy -> 1 -> 1 -> 2 -> 3 -> 4 -> 4
81134
82- Return remaining list:
135+ Return dummy.next.
136+ """
83137
84- 4
85138
86- Final Result:
139+ class Solution :
140+ def mergeTwoLists (self , head1 : Optional [ListNode ], head2 : Optional [ListNode ]) -> Optional [ListNode ]:
87141
88- 1 -> 1 -> 2 -> 3 -> 4 -> 4
142+ dummy = ListNode (0 )
143+ tail = dummy
89144
90- ---------------------------------------------------------
91- Time Complexity: O(m + n)
92- ---------------------------------------------------------
93- m = length of list1
94- n = length of list2
145+ while head1 and head2 :
95146
96- Each node is visited exactly once.
147+ if head1 .val <= head2 .val :
148+ tail .next = head1
149+ head1 = head1 .next
150+ else :
151+ tail .next = head2
152+ head2 = head2 .next
97153
98- ---------------------------------------------------------
99- Space Complexity: O(m + n)
100- ---------------------------------------------------------
101- Recursive call stack can grow up to m + n calls.
154+ tail = tail .next
102155
103- ---------------------------------------------------------
156+ # Attach remaining nodes
157+ if head1 :
158+ tail .next = head1
159+ else :
160+ tail .next = head2
161+
162+ return dummy .next
163+
164+
165+ # =========================================================
166+ # APPROACH 3 : Recursive
167+ # =========================================================
168+ """
169+ Algorithm
170+ ---------
171+ 1. If one list is empty, return the other list.
172+ 2. Compare the first nodes.
173+ 3. Recursively merge the remaining lists.
174+ 4. Return the smaller node as the head.
175+
176+ Time Complexity:
177+ O(m + n)
178+
179+ Space Complexity:
180+ O(m + n)
181+ (Recursive call stack)
104182"""
105183
106- # Definition for singly-linked list.
107- # class ListNode:
108- # def __init__(self, val=0, next=None):
109- # self.val = val
110- # self.next = next
111184
112185class Solution :
113- def mergeTwoLists (
114- self ,
115- list1 : Optional [ListNode ],
116- list2 : Optional [ListNode ]
117- ) -> Optional [ListNode ]:
186+ def mergeTwoLists (self , head1 : Optional [ListNode ], head2 : Optional [ListNode ]) -> Optional [ListNode ]:
118187
119- # Base Case 1:
120- # If list1 is empty, return list2
121- if list1 is None :
122- return list2
188+ if head1 is None :
189+ return head2
123190
124- # Base Case 2:
125- # If list2 is empty, return list1
126- if list2 is None :
127- return list1
191+ if head2 is None :
192+ return head1
128193
129- # Choose the smaller node
130- if list1 .val <= list2 .val :
194+ if head1 .val <= head2 .val :
195+ head1 .next = self .mergeTwoLists (head1 .next , head2 )
196+ return head1
197+ else :
198+ head2 .next = self .mergeTwoLists (head1 , head2 .next )
199+ return head2
131200
132- # Merge the remaining nodes
133- list1 .next = self .mergeTwoLists (
134- list1 .next ,
135- list2
136- )
137201
138- return list1
202+ # =========================================================
203+ # Complexity Analysis
204+ # =========================================================
205+ """
206+ Approach Time Auxiliary Space
207+ ----------------------------------------------------------
208+ Brute Force O(m+n) O(m+n)
209+ Optimal Iterative O(m+n) O(1)
210+ Recursive O(m+n) O(m+n)
211+
212+ where,
213+ m = length of first linked list
214+ n = length of second linked list
215+ """
139216
140- else :
141217
142- # Merge the remaining nodes
143- list2 .next = self .mergeTwoLists (
144- list1 ,
145- list2 .next
146- )
218+ # =========================================================
219+ # Key Interview Points
220+ # =========================================================
221+ """
222+ ✓ Dummy node avoids handling special cases for the head.
223+
224+ ✓ The iterative approach is the most optimal because:
225+ - Every node is visited exactly once.
226+ - No extra linked list is created.
227+ - No recursion stack is used.
228+
229+ ✓ The brute-force approach is easier to understand but
230+ requires additional memory.
231+
232+ ✓ The recursive solution is elegant but uses O(m+n)
233+ auxiliary space due to the recursion stack.
147234
148- return list2
235+ ✓ The iterative in-place approach is the solution most
236+ interviewers expect.
237+ """
0 commit comments