|
| 1 | +--- |
| 2 | +title: LC2095. 删除链表的中间节点 delete-the-middle-node-of-a-linked-list |
| 3 | +date: 2025-09-24 |
| 4 | +categories: [Leetcode-75] |
| 5 | +tags: [leetcode, Leetcode-75, list] |
| 6 | +published: true |
| 7 | +--- |
| 8 | + |
| 9 | +# LC2095. 删除链表的中间节点 delete-the-middle-node-of-a-linked-list |
| 10 | + |
| 11 | + |
| 12 | +给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。 |
| 13 | + |
| 14 | +长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于 x 的最大整数。 |
| 15 | + |
| 16 | +对于 n = 1、2、3、4 和 5 的情况,中间节点的下标分别是 0、1、1、2 和 2 。 |
| 17 | + |
| 18 | +示例 1: |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +输入:head = [1,3,4,7,1,2,6] |
| 23 | +输出:[1,3,4,1,2,6] |
| 24 | +解释: |
| 25 | +上图表示给出的链表。节点的下标分别标注在每个节点的下方。 |
| 26 | +由于 n = 7 ,值为 7 的节点 3 是中间节点,用红色标注。 |
| 27 | +返回结果为移除节点后的新链表。 |
| 28 | + |
| 29 | +示例 2: |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +输入:head = [1,2,3,4] |
| 34 | +输出:[1,2,4] |
| 35 | +解释: |
| 36 | +上图表示给出的链表。 |
| 37 | +对于 n = 4 ,值为 3 的节点 2 是中间节点,用红色标注。 |
| 38 | + |
| 39 | +示例 3: |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +输入:head = [2,1] |
| 44 | +输出:[2] |
| 45 | +解释: |
| 46 | +上图表示给出的链表。 |
| 47 | +对于 n = 2 ,值为 1 的节点 1 是中间节点,用红色标注。 |
| 48 | +值为 2 的节点 0 是移除节点 1 后剩下的唯一一个节点。 |
| 49 | + |
| 50 | + |
| 51 | +提示: |
| 52 | + |
| 53 | +链表中节点的数目在范围 [1, 10^5] 内 |
| 54 | + |
| 55 | +1 <= Node.val <= 10^5 |
| 56 | + |
| 57 | + |
| 58 | +# v1-快慢指针 |
| 59 | + |
| 60 | +## 思路 |
| 61 | + |
| 62 | +### 找到中间节点 |
| 63 | + |
| 64 | +针对这种找中点的链表,最简单的思路是从头到尾遍历,计算出总长度,然后再计算一半的大小,从头到尾再找一次。 |
| 65 | + |
| 66 | +比较推荐的方法是快慢指针。 |
| 67 | + |
| 68 | +快指针一次走2步,慢指针走一步。 |
| 69 | + |
| 70 | +这样,快指针到头时,慢指针就在中间位置。 |
| 71 | + |
| 72 | +### 删除中间节点 |
| 73 | + |
| 74 | +删除的时候,需要考虑一些边界场景 |
| 75 | + |
| 76 | +``` |
| 77 | +pre-middle-next #1 |
| 78 | +pre-middle #2 |
| 79 | +middle-next #3 |
| 80 | +middle #4 |
| 81 | +``` |
| 82 | + |
| 83 | +其实可以简化为2个场景 |
| 84 | + |
| 85 | +1)middle 没有 pre。直接返回 middle.next 作为结果 |
| 86 | + |
| 87 | +2)middle 有 pre。`pre.next = middle.next;` 移除 middle,然后返回以前的 head 即可 |
| 88 | + |
| 89 | +## 实现 |
| 90 | + |
| 91 | +```java |
| 92 | + public ListNode deleteMiddle(ListNode head) { |
| 93 | + ListNode tempHead = head; |
| 94 | + |
| 95 | + // 开始迭代 |
| 96 | + ListNode fast = head; |
| 97 | + ListNode slow = head; |
| 98 | + ListNode slowPre = null; |
| 99 | + while(fast != null) { |
| 100 | + fast = fast.next; |
| 101 | + if(fast == null) { |
| 102 | + break; |
| 103 | + } |
| 104 | + |
| 105 | + // 快走2步 |
| 106 | + fast = fast.next; |
| 107 | + // 慢节点走一步,同时记录慢节点的 pre |
| 108 | + slowPre = slow; |
| 109 | + slow = slow.next; |
| 110 | + } |
| 111 | + |
| 112 | + // slow 就是中点 |
| 113 | + //1. 没有 pre 前,直接返回 slow.next |
| 114 | + if(slowPre == null) { |
| 115 | + return slow.next; |
| 116 | + } |
| 117 | + |
| 118 | + // 移除 middle |
| 119 | + ListNode next = slow.next; |
| 120 | + slowPre.next = next; |
| 121 | + |
| 122 | + // 返回新的头 |
| 123 | + return tempHead; |
| 124 | + } |
| 125 | +``` |
| 126 | + |
| 127 | +## 效果 |
| 128 | + |
| 129 | +3ms 击败 100.00% |
| 130 | + |
| 131 | +## 反思 |
| 132 | + |
| 133 | +快慢指针是链表中的常用技巧,值得掌握。 |
| 134 | + |
| 135 | +# 参考资料 |
0 commit comments