Skip to content
← All posts

Merge In Between Linked Lists: Pointer Surgery

6 min read
leetcodeproblemmediumlinked-lists

Merge In Between Linked Lists is LeetCode problem 1669. You are given two linked lists, list1 and list2, along with two integers a and b. Remove nodes from index a to index b (inclusive) in list1, and splice the entirety of list2 in their place. Return the head of the modified list1.

Think of it as surgical pointer rewiring. You are cutting out a section of one list and stitching another list into the gap. No new nodes are created. No values are copied. You just change where four pointers point.

list1012345a=3b=4list2100000010000011000002result0121000000100000110000025
Nodes 3 and 4 (red) are removed from list1. The entire list2 (green) is spliced in. Yellow arrows show the new connections.

Why this works

The key insight is that you only need to find two nodes in list1:

  • The node at index a - 1 (the last node before the removed section)
  • The node at index b + 1 (the first node after the removed section)

Once you have those two reference points, the splice is just two pointer assignments. You point a - 1's next to the head of list2, and you point the tail of list2 to b + 1. The removed nodes from list1 become unreachable and get garbage collected.

You do not need to explicitly delete the removed nodes. Once nothing points to them, they are effectively gone. In languages with manual memory management (like C++), you would want to free them. In Python, the garbage collector handles it.

The approach

Here is the plan, broken into four clear steps:

  1. Walk to the node at index a - 1. Start from the head and step forward a - 1 times. Save a reference to this node.
  2. Walk to the node at index b + 1. Continue stepping from where you are until you reach the node just past index b. Save a reference.
  3. Connect a - 1 to the head of list2. Set prev.next = list2.
  4. Connect the tail of list2 to b + 1. Walk to the end of list2 and set tail.next = after.

That is the entire algorithm. Four steps, two pointer rewires, and you are done.

Visual walkthrough

Let's trace through the example with list1 = [0, 1, 2, 3, 4, 5], list2 = [1000000, 1000001, 1000002], a = 3, b = 4.

Step 1: Traverse to node at index a-1 (node before removal starts)

list1012345list2100000010000011000002prev (a-1)

Walk from head to index 2 (which is a-1 = 3-1). This is the last node we keep before the removed section.

Step 2: Traverse to node at index b+1 (node after removal ends)

list1012345list2100000010000011000002prev (a-1)after (b+1)

Continue walking to index 5 (which is b+1 = 4+1). This is the first node we keep after the removed section.

Step 3: Point prev.next to list2's head

list1012345list2100000010000011000002prevafter

Rewire prev.next (node 2) to point to the head of list2 (node 1000000). The removed nodes are now disconnected.

Step 4: Point list2's tail to the after node

list1012345list2100000010000011000002prevafter

Walk to the tail of list2 (node 1000002) and point its next to the after node (node 5). The splice is complete.

After step 4, the chain reads 0 -> 1 -> 2 -> 1000000 -> 1000001 -> 1000002 -> 5. Nodes 3 and 4 from the original list1 are no longer reachable from the head. The splice is clean.

The code

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def mergeInBetween(list1, a, b, list2):
    prev = list1
    for _ in range(a - 1):
        prev = prev.next

    after = prev
    for _ in range(b - a + 2):
        after = after.next

    prev.next = list2

    tail = list2
    while tail.next:
        tail = tail.next

    tail.next = after

    return list1

A few things to note about this implementation:

  • prev starts at list1 and moves a - 1 times. After the loop, prev sits at the node immediately before the removal zone.
  • after starts at prev and moves b - a + 2 times. That lands it on the node at index b + 1. The +2 accounts for the fact that you start from prev (which is at a - 1) and need to pass through all b - a + 1 removed nodes, plus one more to land past them.
  • The tail walk is a simple linear scan to the end of list2. You need the last node so you can wire its next to after.
  • Two pointer assignments do the actual splice: prev.next = list2 and tail.next = after.

You can combine the traversal for after into a single pass if you start from prev. Walk forward b - a + 2 steps from prev to land on the node right after the removal zone. This avoids traversing from the head twice.

Complexity analysis

MetricValueReasoning
TimeO(n + m)You traverse list1 up to index b + 1 in O(n) and walk to the tail of list2 in O(m), where n and m are the lengths of the two lists.
SpaceO(1)Only a fixed number of pointer variables are used: prev, after, and tail. No extra data structures.

The time complexity is optimal. You must visit the relevant nodes at least once to find the splice points and the tail of list2. There is no way to do it faster.

The building blocks

This problem is built on one fundamental building block: linked list pointer manipulation.

The core operation is finding a specific node by traversal and then rewiring next pointers to insert, remove, or reroute sections of the list. This same pattern appears in many linked list problems:

  • Reverse Linked List (LeetCode 206) rewires every next pointer in the list to flip the direction.
  • Remove Nth Node From End (LeetCode 19) finds a specific node by traversal and rewires a single pointer to skip it.
  • Swap Nodes in Pairs (LeetCode 24) rewires pairs of next pointers to swap adjacent nodes.
  • Partition List (LeetCode 86) splits a list into two halves and concatenates them, using pointer manipulation at the splice point.

Once you are comfortable finding nodes by index and rewiring next pointers, problems like this become mechanical. The hard part is always the same: making sure you save your references before you overwrite them.

The "find the node before your target" pattern is one of the most reusable techniques in linked list problems. Since singly linked lists do not have backward pointers, you must always position yourself one node earlier than where you want to make a change. Internalize this and most linked list pointer problems become much more approachable.

Edge cases to watch for

  • a equals 1. The node at index a - 1 is index 0, which is the head itself. You still walk a - 1 = 0 steps, so prev stays at head. The splice replaces everything starting from index 1.
  • b is the last index. The node at index b + 1 does not exist, so after becomes None. After the splice, the tail of list2 simply points to None, ending the list.
  • a equals b. You are removing exactly one node. The logic is identical; you still find prev and after, and the splice works the same way.
  • list2 has only one node. The tail walk finishes immediately. The single node gets wired between prev and after. No special handling needed.
  • list2 is very long. The tail walk takes O(m) time. The algorithm still works correctly; it just takes longer to find the end of list2.

From understanding to recall

This problem has a short solution. Five lines of real logic. But the details matter. Do you walk a - 1 steps or a steps for prev? Do you walk b - a + 1 or b - a + 2 steps for after? Which pointer do you set first?

Reading the solution once gives you understanding. But understanding fades. In a week, you will second-guess the off-by-one calculations. You will forget whether after starts from prev or from the head.

Spaced repetition fixes this. You type the solution from scratch today, again in a few days, again after a week. Each rep cements the exact traversal counts and pointer assignments into long-term memory. When this pattern shows up in an interview, you will not hesitate over the details.

Related posts