持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情。
大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
作者简介:
- CSDN C/C++领域新星创作者blog.csdn.net/chuxinchang…
- 掘金LV3用户 juejin.cn/user/138142…
- 阿里云社区专家博主,星级博主,技术博主 developer.aliyun.com/profile/exp…
- 华为云云享专家 bbs.huaweicloud.com/community/m…
题目要求
给定一个头结点为 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 之间。
方法1:统计长度 走两遍
思路:
-
第一步:从头遍历一遍链表得出链表的长度,记为size
-
第二步:从头开始走,走 mid = size/2步 就是链表的中间结点
whle( mid--) ==>这样是循环mid次 while(--mid) ==>这样是循环mid-1次 -
无论是奇数个结点还是偶数个结点都合适
图解
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
//从头开始统计链表长度
struct ListNode* cur = head;
int size = 0;
while(cur)
{
size++;
cur = cur->next;
}
//从头开始重新遍历,走长度的一半步
cur = head;
int mid = size /2;
//走mid步
while(mid--)
{
cur = cur->next;
}
//走完mid步,cur指向的就是中间结点
return cur;
}
方法2:快慢指针
思路
-
定义两个指针,一个fast 一个slow
-
二者从头开始遍历 fast走两步 slow走一步
- fast = fast -> next -> next
- slow = slow ->next
-
奇数个结点结束条件:fast 走到尾结点 (fast ->next NULL)
-
偶数个结点结束条件:fast走到空 (fast == NULL)
因为不知道结点个数是奇数个还是偶数个
所以循环条件可写成
while(fast && fast ->next )
当fast走到NULL 或者 fast->next为空时,&&发生短路,跳出循环
//不可写成 while(fast->next && fast) 可能存在对空指针解引用情况
struct ListNode* middleNode(struct ListNode* head)
{
//定义快慢指针
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast && fast->next)
{
//快指针走两步
fast = fast->next->next;
//慢指针走一步
slow = slow ->next;
}
return slow;
}
易错点:while判断中: fast->next 和fast 顺序
//err
//fast->next可能会对空指针解引用
while(fast->next && fast)
{
//快指针走两步
fast = fast->next->next;
//慢指针走一步
slow = slow ->next;
}