做过链表题目的小伙伴对于如何寻找单链表的“中点”应该不陌生。许多链表题目的“破题点”就在于找到单链表的中间结点。
下面我们就来看四道非常相似的寻找单链表中点的题目:
给定一个带有头结点 head 的非空单链表,
-
若链表为奇数长度返回中点,若链表为偶数长度返回上中点
-
若链表为奇数长度返回中点,若链表为偶数长度返回下中点
-
若链表为奇数长度返回中点前一个,若链表为偶数长度返回上中点前一个
-
若链表为奇数长度返回中点前一个,若链表为偶数长度返回下中点前一个
若链表长度为偶数,则
上中点:中间两个结点中的第一个结点
下中点:中间两个结点中的第二个结点
这四道题均采用 快慢指针 的思想进行解答,即慢指针 slow 走一步,快指针 fast 走两步。
- 但想要完美做出这四道题,关键在于区分好不同情况之间的边界判断条件
问题1
奇数返回中点,偶数返回上中点
public static Node midOrUpMidNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return head;
}
Node slow = head.next;
Node fast = head.next.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
该问题的初始条件判断是三种为空的情况:
不难看出,当链表为空,或仅有 1 个或 2 个结点时,中间结点均为头指针 head 所指向的结点。
当结点的个数超过 3 个时,快慢指针初始设置为:slow = head.next; fast = head.next.next;
当链表结点个数为奇数,循环结束快慢指针的指向情况为:
当链表结点个数为偶数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了偶数结点的上中点。
问题2
奇数返回中点,偶数返回下中点
public static Node midOrDownMidNode(Node head) {
if (head == null || head.next == null) {
return head;
}
Node slow = head.next;
Node fast = head.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
该问题的初始条件判断是两种为空的情况:
当链表为空,或仅有 1 个结点时,中间结点均为头指针 head 所指向的结点。
当结点的个数超过 3 个时,快慢指针初始设置为:slow = head.next; fast = head.next;
当链表结点个数为奇数,循环结束快慢指针的指向情况为:
当链表结点个数为偶数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了偶数结点的下中点。
问题3
奇数返回中点前一个,偶数返回上中点前一个
public static Node midOrUpMidPreNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node slow = head;
Node fast = head.next.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
问题 3 与问题 1 的初始判断条件一致:
当链表为空,或仅有 1 个或 2 个结点时,中点前一个均为头指针 head 。
当结点的个数超过 3 个时,快慢指针初始设置为:slow = head; fast = head.next.next;
当链表结点个数为奇数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了奇数结点的中点前一个。
当链表结点个数为偶数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了偶数结点的上中点的前一个。
问题4
奇数返回中点前一个,偶数返回下中点前一个
public static Node midOrDownMidPreNode(Node head) {
if (head == null || head.next == null) {
return null;
}
if (head.next.next == null) {
return head;
}
Node slow = head;
Node fast = head.next;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
问题 4 的初始判断条件略有不同:
当链表为空,或仅有 1 个结点时,下中点前一个均为 null 。
当链表仅有 2 个结点时,下中点前一个是第一个结点,即 head 。
当结点的个数超过 3 个时,快慢指针初始设置为:slow = head; fast = head.next;
当链表结点个数为奇数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了奇数结点的中点前一个。
当链表结点个数为偶数,循环结束快慢指针的指向情况为:
此时慢指针 slow 指向了偶数结点的下中点的前一个。