From 3c95be01b8229775c22105c153bcca6688ae9f91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 15 Jun 2026 05:36:08 +0000 Subject: [PATCH] feat: add solution for 2095. Delete the Middle Node of a Linked List --- .../analysis.md | 60 ++++++++++++++++ .../problem.md | 72 +++++++++++++++++++ .../solution.go | 35 +++++++++ .../solution_test.go | 51 +++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 problems/2095-delete-the-middle-node-of-a-linked-list/analysis.md create mode 100644 problems/2095-delete-the-middle-node-of-a-linked-list/problem.md create mode 100644 problems/2095-delete-the-middle-node-of-a-linked-list/solution.go create mode 100644 problems/2095-delete-the-middle-node-of-a-linked-list/solution_test.go diff --git a/problems/2095-delete-the-middle-node-of-a-linked-list/analysis.md b/problems/2095-delete-the-middle-node-of-a-linked-list/analysis.md new file mode 100644 index 0000000..342a075 --- /dev/null +++ b/problems/2095-delete-the-middle-node-of-a-linked-list/analysis.md @@ -0,0 +1,60 @@ +# 2095. Delete the Middle Node of a Linked List + +[LeetCode Link](https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/) + +Difficulty: Medium +Topics: Linked List, Two Pointers +Acceptance Rate: 60.0% + +## Hints + +### Hint 1 + +To delete the middle node you first need to *find* it. The middle is the `⌊n / 2⌋th` node (0-based). The naive idea is to walk the whole list once to learn `n`, then walk again to reach the middle. That works — but think about whether there is a way to locate the middle in a **single pass** without counting first. The "Two Pointers" tag is a strong nudge here. + +### Hint 2 + +Consider two pointers that move through the list at different speeds: a `slow` pointer advancing one node per step and a `fast` pointer advancing two nodes per step. When `fast` reaches the end, where does `slow` end up? This "tortoise and hare" technique lets the two pointers naturally meet at the middle. + +### Hint 3 + +Deleting a node in a singly linked list means rewiring its **predecessor** to skip over it (`prev.Next = node.Next`). So you don't just want a pointer *at* the middle — you want a pointer *just before* it. The classic trick is to keep `slow` one step behind by starting `fast` slightly ahead (e.g. advance `fast` by two before the loop, or track a separate `prev`). Don't forget the single-node case: deleting the only node should return an empty list (`nil`). + +## Approach + +We use the **fast/slow two-pointer** pattern to find the node *just before* the middle in one pass, then splice the middle node out. + +Setup: +- If the list has 0 or 1 node, the middle is the head itself; deleting it yields an empty list, so return `nil` immediately. +- Otherwise initialize `slow = head`, `fast = head`, and a `prev` pointer that trails `slow`. + +Traversal: +- Move `fast` forward by two nodes and `slow` forward by one node per iteration, updating `prev` to follow `slow`. +- Loop while `fast != nil && fast.Next != nil`. + +When the loop ends, `slow` sits exactly on the middle node (`⌊n / 2⌋`) and `prev` is the node immediately before it. Why? The fast pointer covers twice the ground, so by the time it falls off the end, the slow pointer has covered half the list — landing on the floor-division midpoint for both odd and even lengths. + +Splice: +- Set `prev.Next = slow.Next`, which unlinks the middle node. +- Return `head` (unchanged, since we never delete the head in this branch). + +Example (`[1,3,4,7,1,2,6]`, n = 7, target index 3 = value 7): +- After the traversal `slow` lands on the node with value `7` and `prev` on `4`. +- `prev.Next = slow.Next` connects `4 -> 1`, producing `[1,3,4,1,2,6]`. ✓ + +Example (`[1,2,3,4]`, n = 4, target index 2 = value 3): +- `slow` lands on `3`, `prev` on `2`, giving `2 -> 4` and result `[1,2,4]`. ✓ + +This is a clean, single-pass solution and a great drill for mastering pointer rewiring. + +## Complexity Analysis + +Time Complexity: O(n) — one traversal where `fast` covers the list at double speed. +Space Complexity: O(1) — only a constant number of pointers are used. + +## Edge Cases + +- **Single node `[x]`**: The only node is the middle. Deleting it must return `nil` (empty list). Handled by the early return. +- **Two nodes `[a,b]`**: n = 2, middle index = 1, so the second node is removed, leaving `[a]`. Verifies that `prev` correctly trails and the head is preserved. +- **Odd vs. even length**: Floor division means the pointer math must land on `⌊n/2⌋` for both parities; the fast/slow setup handles both without special casing. +- **Empty list `nil`**: Although the constraints guarantee at least one node, defensively returning `nil` for a `nil` head keeps the function robust. diff --git a/problems/2095-delete-the-middle-node-of-a-linked-list/problem.md b/problems/2095-delete-the-middle-node-of-a-linked-list/problem.md new file mode 100644 index 0000000..c8986e3 --- /dev/null +++ b/problems/2095-delete-the-middle-node-of-a-linked-list/problem.md @@ -0,0 +1,72 @@ +--- +number: "2095" +frontend_id: "2095" +title: "Delete the Middle Node of a Linked List" +slug: "delete-the-middle-node-of-a-linked-list" +difficulty: "Medium" +topics: + - "Linked List" + - "Two Pointers" +acceptance_rate: 5996.8 +is_premium: false +created_at: "2026-06-15T05:34:48.896774+00:00" +fetched_at: "2026-06-15T05:34:48.896774+00:00" +link: "https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/" +date: "2026-06-15" +--- + +# 2095. Delete the Middle Node of a Linked List + +You are given the `head` of a linked list. **Delete** the **middle node** , and return _the_ `head` _of the modified linked list_. + +The **middle node** of a linked list of size `n` is the `⌊n / 2⌋th` node from the **start** using **0-based indexing** , where `⌊x⌋` denotes the largest integer less than or equal to `x`. + + * For `n` = `1`, `2`, `3`, `4`, and `5`, the middle nodes are `0`, `1`, `1`, `2`, and `2`, respectively. + + + + + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2021/11/16/eg1drawio.png) + + + **Input:** head = [1,3,4,7,1,2,6] + **Output:** [1,3,4,1,2,6] + **Explanation:** + The above figure represents the given linked list. The indices of the nodes are written below. + Since n = 7, node 3 with value 7 is the middle node, which is marked in red. + We return the new list after removing this node. + + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2021/11/16/eg2drawio.png) + + + **Input:** head = [1,2,3,4] + **Output:** [1,2,4] + **Explanation:** + The above figure represents the given linked list. + For n = 4, node 2 with value 3 is the middle node, which is marked in red. + + +**Example 3:** + +![](https://assets.leetcode.com/uploads/2021/11/16/eg3drawio.png) + + + **Input:** head = [2,1] + **Output:** [2] + **Explanation:** + The above figure represents the given linked list. + For n = 2, node 1 with value 1 is the middle node, which is marked in red. + Node 0 with value 2 is the only node remaining after removing node 1. + + + +**Constraints:** + + * The number of nodes in the list is in the range `[1, 105]`. + * `1 <= Node.val <= 105` diff --git a/problems/2095-delete-the-middle-node-of-a-linked-list/solution.go b/problems/2095-delete-the-middle-node-of-a-linked-list/solution.go new file mode 100644 index 0000000..7c6449e --- /dev/null +++ b/problems/2095-delete-the-middle-node-of-a-linked-list/solution.go @@ -0,0 +1,35 @@ +package main + +// 2095. Delete the Middle Node of a Linked List +// +// Approach: fast/slow two pointers (tortoise and hare). +// The fast pointer moves two nodes per step while slow moves one, so when fast +// reaches the end, slow lands on the middle node (floor(n/2), 0-based). We keep +// a `prev` pointer trailing slow so we can splice the middle node out in O(1) +// once it is found. Single pass, constant extra space. + +// ListNode is a node in a singly linked list. +type ListNode struct { + Val int + Next *ListNode +} + +func deleteMiddle(head *ListNode) *ListNode { + // 0 or 1 node: the middle is the head itself; deleting it empties the list. + if head == nil || head.Next == nil { + return nil + } + + var prev *ListNode + slow, fast := head, head + + for fast != nil && fast.Next != nil { + prev = slow + slow = slow.Next + fast = fast.Next.Next + } + + // prev is the node just before the middle; skip over the middle node. + prev.Next = slow.Next + return head +} diff --git a/problems/2095-delete-the-middle-node-of-a-linked-list/solution_test.go b/problems/2095-delete-the-middle-node-of-a-linked-list/solution_test.go new file mode 100644 index 0000000..0a2171a --- /dev/null +++ b/problems/2095-delete-the-middle-node-of-a-linked-list/solution_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "reflect" + "testing" +) + +// buildList constructs a linked list from a slice and returns its head. +func buildList(vals []int) *ListNode { + dummy := &ListNode{} + cur := dummy + for _, v := range vals { + cur.Next = &ListNode{Val: v} + cur = cur.Next + } + return dummy.Next +} + +// toSlice converts a linked list back into a slice for comparison. +func toSlice(head *ListNode) []int { + var out []int + for node := head; node != nil; node = node.Next { + out = append(out, node.Val) + } + return out +} + +func TestSolution(t *testing.T) { + tests := []struct { + name string + input []int + expected []int + }{ + {"example 1: odd length, removes index 3", []int{1, 3, 4, 7, 1, 2, 6}, []int{1, 3, 4, 1, 2, 6}}, + {"example 2: even length, removes index 2", []int{1, 2, 3, 4}, []int{1, 2, 4}}, + {"example 3: two nodes, removes second", []int{2, 1}, []int{2}}, + {"edge case: single node becomes empty", []int{42}, nil}, + {"edge case: three nodes removes middle", []int{10, 20, 30}, []int{10, 30}}, + {"edge case: five nodes removes index 2", []int{5, 4, 3, 2, 1}, []int{5, 4, 2, 1}}, + {"edge case: empty input", nil, nil}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := toSlice(deleteMiddle(buildList(tt.input))) + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("deleteMiddle(%v) = %v, want %v", tt.input, got, tt.expected) + } + }) + } +}