1. 题目
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next =
NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
提示:
给定链表的结点数介于 1 和 100 之间。
Related Topics 链表 双指针
👍 353 👎 0
2. 题解
2.1 解法1: 快慢指针
class Solution {
public ListNode middleNode(ListNode head) {
if (head == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
2.2 解法2: 两次遍历
第一次遍历计算链表的长度, 然后得出中点位置, 然后再遍历找到中间结点
class Solution {
public ListNode middleNode(ListNode head) {
if (head == null) {
return null;
}
ListNode cur = head;
int len = 0;
while (cur != null) {
len++;
cur = cur.next;
}
int k = len / 2;
cur = head;
while (k > 0) {
cur = cur.next;
k--;
}
return cur;
}
}
3. 链表问题常用技巧
- 使用递归函数,避免复杂的更改指针变量指向操作,使得求解问题变得简单。
「力扣」第 206 题:反转链表;
「力扣」第 24 题:两两交换链表中的节点;
「力扣」第 25 题:K 个一组翻转链表;
「力扣」第 328 题:奇偶链表;
「力扣」第 203 题:移除链表元素;
「力扣」第 21 题:合并两个有序链表。 - 设置「虚拟头结点」,避免对链表第 1 个结点做单独讨论,这个思想在数组里我们见过,叫「哨兵」;
「力扣」第 2 题:两数相加;
「力扣」第 82 题:删除排序链表中的重复元素 II。 - 使用「快慢指针」,本题就是。确切地说,叫「同步指针」可能更好一些;
- 打草稿很重要: 绝大多数时候在草稿纸上写写画画就能得到解决链表问题的办法,特别是在链表中做一些更改指针变量指向操作的问题
- 为链表编写测试函数,进行调试(在下面的参考代码中有),主要是:
从数组得到一个链表;
根据当前结点打印当前结点以及后面的结点。
这两个方法可以非常方便地帮助我们调试关于链表的程序。