Lesson 45 of 164
Merge Two Sorted Linked Lists
Given the heads of two sorted linked lists, merge them into one sorted list made by splicing together the nodes of the two lists, and return its head.
LeetCode: 21. Merge Two Sorted Lists
Example
Input: 1 -> 2 -> 4, 1 -> 3 -> 4
Output: 1 -> 1 -> 2 -> 3 -> 4 -> 4Brute force: collect and sort
A Java list node is an object with a mutable next field. null marks the end of the list, so an empty list is null and no wrapper type is needed.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
static class ListNode {
int val;
ListNode next;
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
List<Integer> values = new ArrayList<>();
for (ListNode n = l1; n != null; n = n.next) values.add(n.val);
for (ListNode n = l2; n != null; n = n.next) values.add(n.val);
Collections.sort(values);
ListNode head = null;
for (int i = values.size() - 1; i >= 0; i--) {
head = new ListNode(values.get(i), head);
}
return head;
}
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static String show(ListNode list) {
StringBuilder sb = new StringBuilder("[");
for (ListNode n = list; n != null; n = n.next) {
if (n != list) sb.append(", ");
sb.append(n.val);
}
return sb.append("]").toString();
}
public static void main(String[] args) {
System.out.println(show(mergeTwoLists(fromArray(1, 2, 4), fromArray(1, 3, 4))));
}
}[1, 1, 2, 3, 4, 4]Time: O((m + n) log(m + n)). Space: O(m + n). It ignores that the inputs are sorted, and it allocates new nodes.
Optimal: splice the nodes
Compare the two heads, detach the smaller one from its list, and append it to the result. A dummy node placed before the result gives tail a node to attach to, so the first append needs no special case. When one list runs out, the rest of the other is already sorted and is attached in one step.
public class Main {
static class ListNode {
int val;
ListNode next;
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0, null);
ListNode tail = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
tail.next = l1;
l1 = l1.next;
} else {
tail.next = l2;
l2 = l2.next;
}
tail = tail.next;
}
tail.next = (l1 != null) ? l1 : l2;
return dummy.next;
}
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static String show(ListNode list) {
StringBuilder sb = new StringBuilder("[");
for (ListNode n = list; n != null; n = n.next) {
if (n != list) sb.append(", ");
sb.append(n.val);
}
return sb.append("]").toString();
}
public static void main(String[] args) {
System.out.println(show(mergeTwoLists(fromArray(1, 2, 4), fromArray(1, 3, 4))));
System.out.println(show(mergeTwoLists(fromArray(), fromArray(0))));
System.out.println(show(mergeTwoLists(fromArray(5, 6), fromArray(1, 2, 3))));
}
}[1, 1, 2, 3, 4, 4]
[0]
[1, 2, 3, 5, 6]Time: O(m + n). Space: O(1): the existing nodes are reused. The merged list shares nodes with the inputs, so the input lists must not be used after the merge.
Edge cases
- One or both lists empty: the loop does not run, and
tail.nextreceives whichever list is notnull(ornullwhen both are empty). - Equal values:
<=takes froml1first, which keeps the merge stable.
