淘先锋技术网

首页 1 2 3 4 5 6 7

链表中间结点

leetcode题目链接:876. 链表的中间结点
在这里插入图片描述

一、朴素解法

最直观的思路,因为不知道这个链表的长度,就先通过一次循环统计链表的长度len
之后第二次遍历,直到找到中间结点,输出

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 
struct ListNode* middleNode(struct ListNode* head){
    struct ListNode *p = head;
    int len = 0, t = 0;
    // 统计链表长度len
    while(p){
        len++;
        p = p->next;
    }
    p = head;
    while(1){
        if((t==((len-1)/2))&&(len%2!=0)){
            return p;
        }
        if((t==(len/2))&&(len%2==0)){
            return p;
        }
        p = p->next;
        t++;
    }
}

结果:

在这里插入图片描述

二、快慢指针

通过分析发现,第一次遍历几乎没做什么事,就是统计了一下链表的长度,当链表长度很长时,就会浪费大量的时间。
采用快慢指针,快指针一次走两步,慢指针一次走一步,这样当快指针走到链表结尾时,慢指针正好指向中间节点。

1. len = 2n

Eg. len = 4

第一步(初始状态)

快慢指针都指向第一个节点(头节点)
在这里插入图片描述

第二步

快指针前进两步,慢指针前进一步
在这里插入图片描述

第三步

快指针到达链表末尾,此时慢指针正好指向题目要求的偶数个数的第二个中间节点,结束循环,
结束条件: fast == NULL
在这里插入图片描述

2. len = 2n+1

Eg. len = 5

第一步 (初始状态)

在这里插入图片描述

第二步

快指针前进两步,慢指针前进一步
在这里插入图片描述

第三步

虽然此时快指针没有到达链表结尾,但是此时慢指针已经到达了链表中间,此时应该标记为结束标志结束循环,否则快指针去找NULL的next就会出错
判断条件: fast->next == NULL
在这里插入图片描述
因此可以得到两种情况下的结束条件是 fast && fast->next

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode *p_fast = head, *p_slow = head;
    while(p_fast && p_fast->next){
        p_fast = p_fast->next->next;
        p_slow = p_slow->next;
    }
    return p_slow;
}

在这里插入图片描述