【leetcode天梯】链表 · 876 查找链表中间结点

题目描述:

给定一个头结点为 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,我们返回第二个结点。

题目链接:

876. 链表的中间结点 - 力扣(LeetCode)icon-default.png?t=M666https://leetcode.cn/problems/middle-of-the-linked-list/submissions/


解题思路:

常规法1:快慢指针

这是一道经典的题目,使用到了快慢指针。其中快指针一次走两步,慢指针一次走一步,当快指针走到空时,慢指针刚好走到一半。

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow=head;
    if(head==NULL) //如果为空链表,那么fast起初就不存在
        return NULL;
    struct ListNode* fast=head->next;
    while(fast)
    {
        fast=fast->next; //不管是偶数个结点还是奇数个结点,fast的倒数第二步都不会出现空指针情形
        if(fast!=NULL) //最后一步时,fast可能已经为空,这时就无须再向后走一步了
            fast=fast->next;
        slow=slow->next; //slow每次向后走一步
    }
    return slow;
}

总结一下:我们在这里使用快慢指针的操作来找中间结点,但是这个方法有两个地方需要值得注意:

  • 第一点就是当原链表是一个空链表时,是找不到fast的初始指针的位置的,如果直接执行fast=head->next;可能会出现空指针错误。
  • 第二点就是在循环遍历的过程中,fast指针在最后两步进入NULL时,当原链表为偶数个结点时,倒数第二步就已经进入NULL了,此时如果直接执行第二个fast=fast->next;依然会出现空指针错误。

那么我们有没有办法再简化一下这样的操作呢?那是肯定的!

常规法2:快慢指针改进版

其实我们可以针对第一种方法的两个特点进行改进,首先是第一点,初始时,我们不妨将fast指针和slow都指向head,这样就不用特地考虑原链表为空时,fast指向NULL->next情况。但是更改了这个,我们同时就需要修改循环的结束条件,我们可以通过作图来寻找偶数个结点和奇数个结点两种情况下满足slow指向中间结点时fast结束的位置:

扫描二维码关注公众号,回复: 14393617 查看本文章
  • 链表结点数为奇数时:fast->next为NULL时结束遍历。
  • 链表结点数为偶数时:fast为NULL时结束遍历。

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow = head; //快慢指针都指向链表的第一个结点
    struct ListNode* fast = head;
    while(fast&&fast->next) //只要这两个有一个满足为NULL,说明slow就指向了链表中间结点
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

猜你喜欢

转载自blog.csdn.net/qq_54151955/article/details/125957246