链表中间结点
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;
}