🧠
Brute Force (Recursive Merge)
💡 This approach uses recursion to merge lists by always choosing the smaller head node. It helps beginners understand the problem's recursive structure but can cause stack overflow for very long lists.
Intuition
At each step, compare the heads of both lists and pick the smaller one as the next node in the merged list, then recursively merge the rest.
Algorithm
- If either list is empty, return the other list.
- Compare the current nodes of both lists.
- Recursively set the next pointer of the smaller node to the result of merging the rest.
- Return the smaller node as the head of the merged list.
💡 The recursion naturally breaks down the problem into smaller merges, but keeping track of recursive calls can be tricky at first.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def mergeTwoLists(l1, l2):
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
l1.next = mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = mergeTwoLists(l1, l2.next)
return l2
# Driver code to test
if __name__ == '__main__':
# Helper to create linked list from list
def create_list(arr):
head = ListNode(arr[0]) if arr else None
current = head
for val in arr[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper to print linked list
def print_list(node):
vals = []
while node:
vals.append(str(node.val))
node = node.next
print('[' + ','.join(vals) + ']')
l1 = create_list([1,2,4])
l2 = create_list([1,3,4])
merged = mergeTwoLists(l1, l2)
print_list(merged)
Line Notes
if not l1:Base case: if first list is empty, return second list directly
if not l2:Base case: if second list is empty, return first list directly
if l1.val < l2.val:Compare current nodes to decide which node to pick next
l1.next = mergeTwoLists(l1.next, l2)Recursively merge the rest of l1 with l2 and link to current node
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
public static void main(String[] args) {
Solution sol = new Solution();
ListNode l1 = new ListNode(1, new ListNode(2, new ListNode(4)));
ListNode l2 = new ListNode(1, new ListNode(3, new ListNode(4)));
ListNode merged = sol.mergeTwoLists(l1, l2);
printList(merged);
}
static void printList(ListNode node) {
while (node != null) {
System.out.print(node.val);
if (node.next != null) System.out.print(",");
node = node.next;
}
System.out.println();
}
}
Line Notes
if (l1 == null) return l2;Return second list if first is empty, base case
if (l2 == null) return l1;Return first list if second is empty, base case
if (l1.val < l2.val)Choose node with smaller value to continue merged list
l1.next = mergeTwoLists(l1.next, l2);Recursively merge remaining nodes and link
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (!l1) return l2;
if (!l2) return l1;
if (l1->val < l2->val) {
l1->next = mergeTwoLists(l1->next, l2);
return l1;
} else {
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
// Helper functions
ListNode* createList(int arr[], int n) {
if (n == 0) return nullptr;
ListNode* head = new ListNode(arr[0]);
ListNode* current = head;
for (int i = 1; i < n; i++) {
current->next = new ListNode(arr[i]);
current = current->next;
}
return head;
}
void printList(ListNode* head) {
while (head) {
cout << head->val;
if (head->next) cout << ",";
head = head->next;
}
cout << endl;
}
int main() {
int arr1[] = {1,2,4};
int arr2[] = {1,3,4};
ListNode* l1 = createList(arr1, 3);
ListNode* l2 = createList(arr2, 3);
Solution sol;
ListNode* merged = sol.mergeTwoLists(l1, l2);
printList(merged);
return 0;
}
Line Notes
if (!l1) return l2;Base case: if first list is empty, return second
if (!l2) return l1;Base case: if second list is empty, return first
if (l1->val < l2->val)Pick smaller node to continue merged list
l1->next = mergeTwoLists(l1->next, l2);Recursively merge remaining nodes and link
function ListNode(val, next = null) {
this.val = val;
this.next = next;
}
function mergeTwoLists(l1, l2) {
if (!l1) return l2;
if (!l2) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
// Helper to create linked list from array
function createList(arr) {
if (arr.length === 0) return null;
let head = new ListNode(arr[0]);
let current = head;
for (let i = 1; i < arr.length; i++) {
current.next = new ListNode(arr[i]);
current = current.next;
}
return head;
}
// Helper to print linked list
function printList(node) {
let vals = [];
while (node) {
vals.push(node.val);
node = node.next;
}
console.log('[' + vals.join(',') + ']');
}
// Test
const l1 = createList([1,2,4]);
const l2 = createList([1,3,4]);
const merged = mergeTwoLists(l1, l2);
printList(merged);
Line Notes
if (!l1) return l2;Return second list if first is empty, base case
if (!l2) return l1;Return first list if second is empty, base case
if (l1.val < l2.val)Choose smaller node to continue merged list
l1.next = mergeTwoLists(l1.next, l2);Recursively merge remaining nodes and link
TimeO(n + m)
SpaceO(n + m) due to recursion stack
Each node is visited once, but recursion adds stack frames proportional to total nodes.
💡 For lists of length 20 and 30, expect about 50 recursive calls, which is manageable but can cause stack overflow for very large lists.
Interview Verdict: Accepted but not optimal for very large lists due to recursion depth
This approach is easy to understand and implement but can fail on very large inputs due to recursion limits.