This page collects battle-tested Python templates for every major linked-list pattern you’ll see on LeetCode. Each section includes ready-to-use code, the signal phrases that tell you which pattern to reach for, and a quick explanation of the core idea. Bookmark it, copy what you need, and focus your energy on the actual problem logic.

New to Linked Lists? A linked list is a chain of nodes where each node points to the next. Unlike arrays, you can’t jump to index i — you must walk from the head. The tradeoff: O(1) insert/delete at known positions, but O(n) access.

Basic linked list head 1 2 3 null Dummy node pattern dummy 0 head 1 2 3 null

Contents

ListNode Definition

When to use: Every linked-list problem — this is the building block. Know the struct by heart so you never waste time on boilerplate.

Standard Definition

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

Alternative Definitions

# Optional typing style
from typing import Optional


class ListNode:
    def __init__(self, val: int = 0, next: Optional["ListNode"] = None):
        self.val = val
        self.next = next

Common Construction Methods

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


def create_list(values: list[int]) -> ListNode | None:
    if not values:
        return None
    head = ListNode(values[0])
    cur = head
    for x in values[1:]:
        cur.next = ListNode(x)
        cur = cur.next
    return head


def create_list_recursive(values: list[int], index: int = 0) -> ListNode | None:
    if index >= len(values):
        return None
    node = ListNode(values[index])
    node.next = create_list_recursive(values, index + 1)
    return node


def create_list_dummy(values: list[int]) -> ListNode | None:
    dummy = ListNode(0)
    cur = dummy
    for val in values:
        cur.next = ListNode(val)
        cur = cur.next
    return dummy.next

Utility Functions

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


def print_list(head: ListNode | None) -> None:
    parts: list[str] = []
    cur = head
    while cur:
        parts.append(str(cur.val))
        cur = cur.next
    print(" -> ".join(parts))


def get_length(head: ListNode | None) -> int:
    n = 0
    cur = head
    while cur:
        n += 1
        cur = cur.next
    return n


def list_to_array(head: ListNode | None) -> list[int]:
    out: list[int] = []
    cur = head
    while cur:
        out.append(cur.val)
        cur = cur.next
    return out

Example Usage

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


def create_list(values: list[int]) -> ListNode | None:
    if not values:
        return None
    h = ListNode(values[0])
    c = h
    for x in values[1:]:
        c.next = ListNode(x)
        c = c.next
    return h


head = create_list([1, 2, 3, 4, 5])
# print_list(head)  # 1 -> 2 -> 3 -> 4 -> 5
# get_length(head) == 5
# list_to_array(head) == [1, 2, 3, 4, 5]

Basic Operations

When to use: You need to “visit every node”, “count nodes”, “find a value”, or “collect values into an array”. Also the foundation for insert/delete at arbitrary positions.

Traversal

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


def traverse(head: ListNode | None) -> None:
    cur = head
    while cur:
        _ = cur.val
        cur = cur.next


def traverse_recursive(head: ListNode | None) -> None:
    if not head:
        return
    _ = head.val
    traverse_recursive(head.next)

Insertion

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


def insert_at_head(head: ListNode | None, val: int) -> ListNode:
    node = ListNode(val, head)
    return node


def insert_after(node: ListNode, val: int) -> None:
    node.next = ListNode(val, node.next)

Deletion

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


def delete_node_copy(node: ListNode) -> None:
    assert node.next
    node.val = node.next.val
    node.next = node.next.next


def delete_value(head: ListNode | None, val: int) -> ListNode | None:
    if not head:
        return None
    if head.val == val:
        return head.next
    cur = head
    while cur.next:
        if cur.next.val == val:
            cur.next = cur.next.next
            break
        cur = cur.next
    return head

ID Title Link Solution
203 Remove Linked List Elements Link Solution
237 Delete Node in a Linked List Link -

Two Pointers

When to use: The problem says “middle of list”, “kth from end”, “intersection of two lists”, or “split list into halves”. Use fast/slow pointers to solve in one pass without knowing the length.

Fast and Slow Pointers

slow moves 1 step · fast moves 2 steps Initial slow fast 1 2 3 4 5 Step 1 slow fast 1 2 3 4 5 Step 2 slow fast 1 2 3 middle 4 5
class ListNode:
    def __init__(self, val: int = 0, next=None):
        self.val = val
        self.next = next


def find_middle(head: ListNode | None) -> ListNode | None:
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow


def find_kth_from_end(head: ListNode | None, k: int) -> ListNode | None:
    fast = head
    for _ in range(k):
        if fast is None:
            return None
        fast = fast.next
    slow = head
    while fast:
        slow = slow.next
        fast = fast.next
    return slow

Two Pointers for Partitioning

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


def partition(head: ListNode | None, x: int) -> ListNode | None:
    less = ListNode(0)
    greater = ListNode(0)
    less_cur, greater_cur = less, greater
    while head:
        if head.val < x:
            less_cur.next = head
            less_cur = less_cur.next
        else:
            greater_cur.next = head
            greater_cur = greater_cur.next
        head = head.next
    greater_cur.next = None
    less_cur.next = greater.next
    return less.next

ID Title Link Solution
876 Middle of the Linked List Link Solution
19 Remove Nth Node From End of List Link -

Dummy Node Pattern

When to use: The problem involves “delete head”, “merge lists”, “insert at front”, or any operation where the head might change. A dummy node in front of head eliminates null-check edge cases.

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


def remove_elements(head: ListNode | None, val: int) -> ListNode | None:
    dummy = ListNode(0, head)
    cur = dummy
    while cur.next:
        if cur.next.val == val:
            cur.next = cur.next.next
        else:
            cur = cur.next
    return dummy.next

Key Benefits:

  • Handles empty list case
  • Simplifies head deletion
  • Reduces special case handling
ID Title Link Solution
203 Remove Linked List Elements Link Solution

Reversal

When to use: The problem says “reverse linked list”, “reverse between positions”, “reverse in groups of k”, or “palindrome linked list”. The core trick is rewiring next pointers as you walk.

Reverse Entire List

Step 1 prev curr next null 1 2 3 4 Step 2 prev curr next null 1 2 3 4 Step 3 prev curr next null 1 2 3 4 ← reversed → original
class ListNode:
    def __init__(self, val: int = 0, next=None):
        self.val = val
        self.next = next


def reverse_list(head: ListNode | None) -> ListNode | None:
    prev, cur = None, head
    while cur:
        nxt = cur.next
        cur.next = prev
        prev = cur
        cur = nxt
    return prev


def reverse_list_recursive(head: ListNode | None) -> ListNode | None:
    if not head or not head.next:
        return head
    new_head = reverse_list_recursive(head.next)
    head.next.next = head
    head.next = None
    return new_head

Reverse Between Positions

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


def reverse_between(head: ListNode | None, left: int, right: int) -> ListNode | None:
    dummy = ListNode(0, head)
    prev = dummy
    for _ in range(left - 1):
        prev = prev.next
    cur = prev.next
    for _ in range(right - left):
        nxt = cur.next
        cur.next = nxt.next
        nxt.next = prev.next
        prev.next = nxt
    return dummy.next

Reverse in Groups

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


def reverse_k_group(head: ListNode | None, k: int) -> ListNode | None:
    cur = head
    for _ in range(k):
        if cur is None:
            return head
        cur = cur.next
    prev, cur = None, head
    for _ in range(k):
        nxt = cur.next
        cur.next = prev
        prev, cur = cur, nxt
    head.next = reverse_k_group(cur, k)
    return prev

ID Title Link Solution
206 Reverse Linked List Link Solution
92 Reverse Linked List II Link Solution
25 Reverse Nodes in k-Group Link Solution
24 Swap Nodes in Pairs Link Solution

Merge

When to use: The problem says “merge two sorted lists”, “merge k sorted lists”, or “add two numbers represented as lists”. Compare heads, advance the smaller, and use a dummy node to collect the result.

Merge Two Sorted Lists

list1 1 3 5 list2 2 4 6 result 1 2 3 4 5 6 from list1 from list2
class ListNode:
    def __init__(self, val: int = 0, next=None):
        self.val = val
        self.next = next


def merge_two_lists(list1: ListNode | None, list2: ListNode | None) -> ListNode | None:
    dummy = ListNode(0)
    cur = dummy
    while list1 and list2:
        if list1.val <= list2.val:
            cur.next = list1
            list1 = list1.next
        else:
            cur.next = list2
            list2 = list2.next
        cur = cur.next
    cur.next = list1 or list2
    return dummy.next

Merge K Sorted Lists

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


def merge_two_lists(a: ListNode | None, b: ListNode | None) -> ListNode | None:
    dummy = ListNode(0)
    cur = dummy
    while a and b:
        if a.val <= b.val:
            cur.next, a = a, a.next
        else:
            cur.next, b = b, b.next
        cur = cur.next
    cur.next = a or b
    return dummy.next


def merge_k_lists(lists: list[ListNode | None]) -> ListNode | None:
    if not lists:
        return None

    def helper(lo: int, hi: int) -> ListNode | None:
        if lo == hi:
            return lists[lo]
        mid = (lo + hi) // 2
        return merge_two_lists(helper(lo, mid), helper(mid + 1, hi))

    return helper(0, len(lists) - 1)

ID Title Link Solution
21 Merge Two Sorted Lists Link -
23 Merge k Sorted Lists Link Solution
2 Add Two Numbers Link Solution
1669 Merge In Between Linked Lists Link Solution

Cycle Detection

When to use: The problem asks “has cycle”, “find cycle start”, or “find the duplicate number” (which reduces to cycle detection). Floyd’s algorithm: if fast and slow meet, there’s a cycle.

Detect Cycle (Floyd’s Algorithm)

Phase 1 — fast and slow meet 1 2 3 cycle start 4 5 cycle slow fast meet here! Phase 2 — reset slow to head, both advance ×1 1 2 3 4 5 slow (reset) fast ↑ cycle start — both meet here
class ListNode:
    def __init__(self, val: int = 0, next=None):
        self.val = val
        self.next = next


def has_cycle(head: ListNode | None) -> bool:
    if not head or not head.next:
        return False
    slow, fast = head, head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow is fast:
            return True
    return False


def detect_cycle(head: ListNode | None) -> ListNode | None:
    slow, fast = head, head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow is fast:
            break
    else:
        return None
    slow = head
    while slow is not fast:
        slow = slow.next
        fast = fast.next
    return slow

ID Title Link Solution
141 Linked List Cycle Link -
142 Linked List Cycle II Link -

Circular Linked List

When to use: The problem mentions “circular linked list”, “sorted circular list”, or “rotate list”. The key difference from normal lists: the tail’s next points back to the head instead of nullptr.

Insert into Sorted Circular List

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


def insert_circular(head: ListNode | None, insert_val: int) -> ListNode:
    if not head:
        node = ListNode(insert_val)
        node.next = node
        return node
    prev, cur = head, head.next
    while cur is not head:
        if prev.val <= insert_val <= cur.val:
            break
        if prev.val > cur.val and (insert_val >= prev.val or insert_val <= cur.val):
            break
        prev, cur = cur, cur.next
    prev.next = ListNode(insert_val, cur)
    return head

ID Title Link Solution
708 Insert into a Sorted Circular Linked List Link Solution
382 Linked List Random Node Link Solution

Quick-Reference Summary

Pattern Signal Phrases Key Idea
Two Pointers “middle”, “kth from end”, “intersection” Fast moves 2x, slow moves 1x
Dummy Node “delete head”, “merge”, “insert at front” Avoids null-check edge cases
Reversal “reverse list”, “reverse between” Rewire next pointers
Merge “merge sorted”, “merge k lists” Compare heads, advance smaller
Cycle Detection “has cycle”, “cycle start” Floyd’s: fast meets slow = cycle

More templates