今天的学习重点是快慢指针法求解关于环形链表的那些事
快慢指针法:
主要是指一个遍历链表的方法,我们通过fast和slow两个指针进行遍历链表。
我们规定为fast每次走两步,slow则每次走一步
以此的根据下对不同的题目进行不同的变动
876.链表的中间结点
(1)题目描述
题目链接如下:
力扣876. 链表的中间结点http://leetcode.cn/problems/middle-of-the-linked-list/description/
给定一个头结点为 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
之间。
做题分析:
用自己的话解释题意:
把一个链表,找到链表最中间的节点。
开始思考解决方法:
这一题,因为恰巧我们是要寻找中间的节点
那么也刚好对应了我们的快慢指针的一个走法。
当我们fast指针走到末尾或者末尾的空指针时,slow指针就刚好处于中间节点。
只需要特判fast的状态即可。
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *sl,*fa;
sl=head;
fa=head;
while(fa!=NULL&&fa->next!=NULL){
sl=sl->next;
fa=fa->next->next;
}
return sl;
}
};
141.环形链表
(1)题目描述
题目链接如下:
力扣141. 环形链表https://leetcode.cn/problems/linked-list-cycle/description/
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引 。
做题分析:
用自己的话解释题意:
把一个链表,判断是否有环。
开始思考解决方法:
这一题问题也是不大,因为只要有环的话,那么两个指针一定会陷入到环里,
那么处于最开始前面的fast指针一定会在环里和slow指针相遇。
那我们的循环遍历条件只要稍加改正即可。
具体代码实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==nullptr||head->next==nullptr)return false;
ListNode *l,*f;
l=head;
f=head->next;
while(l!=f){
if(f==NULL||f->next==NULL)return false;
l=l->next;
f=f->next->next;
}
return true;
}
};
142.环形链表 II
(1)题目描述
题目链接如下:
力扣142. 环形链表 IIhttp://leetcode.cn/problems/linked-list-cycle-ii/description/
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。
提示:
- 链表中节点的数目范围在范围
[0, 104]
内 -105 <= Node.val <= 105
pos
的值为-1
或者链表中的一个有效索引
做题分析:
用自己的话解释题意:
把一个链表,判断环的起点。
开始思考解决方法:
这题在写的过程中有着很大的问题。
刚开始以为就是一道平平无奇的快慢指针法。
但是左思右想都差点意思好像。
发现我们需要推论一些结论之后才能得出本题的方法
那么以下就是我通过看题解之后得出的结论:
我们设置a为head到环入口的距离
b为环入口到fast和slow相遇的距离
c为环的剩余距离
那么我们可得出图片上的结论
那么接下来一个简单但又不简单的推导
我们a-c是不是相当于,把head节点往前走了c步
那么如果我们相遇的slow节点同时也运动c步是不是就到达了环的入口
那么接下来的(a-c)=(k-1)(b+c)
是不是就代表,head节点往前走了c步后,与环的入口剩余距离时环的整数倍。那么我们
又因为slow此时也走了c步,那么接下来如果继续同步运动的话
head和slow相遇的地方就是环的入口。
我们代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *sl,*fa;
fa=head;
sl=head;
while(fa!=NULL&&fa->next!=NULL){
fa=fa->next->next;
sl=sl->next;
if(fa==sl){
while(head!=sl){
sl=sl->next;
head=head->next;
}
return head;
}
}return NULL;
}
};
二、总结及计划
今天,第三道题完全给我搞不会了
心态直接写炸了
为啥还有这么多数学推导。
不过看了很久的讲解和不同的方法也算是理解了
文章里的思路和讲解引用这个视频里的环形链表的入口怎么找?一个视频讲透快慢指针!【基础算法精讲 07】链表的中间结点 | 环形链表II | 重排链表 | 力扣 LeetCode 高频面试题_哔哩哔哩_bilibili
早早睡觉了。
越是痛苦越是成长了,坚持打卡。