Post

Linked List: Merge Two Sorted Lists — Kotlin Solution

Linked List: Merge Two Sorted Lists — Kotlin Solution

Problem Info

  
LeetCode #21 — Merge Two Sorted Lists
DifficultyEasy
TopicLinked List, Recursion

Given the heads of two sorted linked lists list1 and list2, merge them into one sorted list and return the head.

Example:

1
2
3
4
Input:  list1 = 1 → 2 → 4
        list2 = 1 → 3 → 4

Output: 1 → 1 → 2 → 3 → 4 → 4

The Node Definition

1
2
3
class ListNode(var `val`: Int) {
    var next: ListNode? = null
}

Approach

Like merging two sorted arrays — but with pointers instead of indices.

The dummy node trick — create a fake head to avoid special-casing an empty result list.

Walk through:

1
2
3
4
5
6
7
8
9
10
11
12
list1: 1 → 2 → 4
list2: 1 → 3 → 4

dummy → ?
Compare 1 vs 1: pick list1(1), list1 = 2 → 4
Compare 2 vs 1: pick list2(1), list2 = 3 → 4
Compare 2 vs 3: pick list1(2), list1 = 4
Compare 4 vs 3: pick list2(3), list2 = 4
Compare 4 vs 4: pick list1(4), list1 = null
Remaining: append list2(4)

Result: 1 → 1 → 2 → 3 → 4 → 4 ✓

Kotlin Solution

Approach 1 — Iterative (with dummy node)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun mergeTwoLists(list1: ListNode?, list2: ListNode?): ListNode? {
    val dummy = ListNode(0)
    var current: ListNode = dummy
    var l1 = list1
    var l2 = list2

    while (l1 != null && l2 != null) {
        if (l1.`val` <= l2.`val`) {
            current.next = l1
            l1 = l1.next
        } else {
            current.next = l2
            l2 = l2.next
        }
        current = current.next!!
    }

    current.next = l1 ?: l2  // attach remaining nodes

    return dummy.next
}

Approach 2 — Recursive

1
2
3
4
5
6
7
8
9
10
11
12
fun mergeTwoLists(list1: ListNode?, list2: ListNode?): ListNode? {
    if (list1 == null) return list2
    if (list2 == null) return list1

    return if (list1.`val` <= list2.`val`) {
        list1.next = mergeTwoLists(list1.next, list2)
        list1
    } else {
        list2.next = mergeTwoLists(list1, list2.next)
        list2
    }
}

Why Kotlin Shines Here

Elvis operator ?: — attach remaining list in one line:

1
2
current.next = l1 ?: l2
// vs Java: current.next = (l1 != null) ? l1 : l2;

if as expression — recursive solution reads as pure logic:

1
2
3
4
5
return if (list1.`val` <= list2.`val`) {
    list1.next = mergeTwoLists(list1.next, list2)
    list1
} else { ... }
// No ternary gymnastics needed

current.next!! — we just assigned current.next above, safe to use !! here:

1
current = current.next!!

Why the Dummy Node?

1
2
3
4
5
6
7
8
// Without dummy — messy special case
var head: ListNode? = null
// need to check if head is null on first iteration...

// With dummy — clean always
val dummy = ListNode(0)
var current: ListNode = dummy
// current is always non-null — no branching needed

One allocation, saves a lot of branching.


Complexity

  
TimeO(m + n) — visit every node in both lists
SpaceO(1) iterative / O(m+n) recursive

Key Takeaway

Dummy head eliminates empty-list edge cases. Compare, attach the smaller node, advance. Attach the remaining non-null list at the end.

🔗 Solve it on LeetCode →


📚 Kotlin DSA Series

This post is part of the Kotlin DSA series — solving LeetCode problems using idiomatic Kotlin.

← View Full Series Index
This post is licensed under CC BY 4.0 by the author.