目录
141. 环形链表
问题描述:
实现代码与解析:
快慢指针:
原理思路:
142. 环形链表 II
问题描述:
实现代码与解析:
快慢指针
原理思路:
143. 重排链表
题目描述:
实现代码与解析:
线性表
原理思路:
141. 环形链表
问题描述:
给你一个链表的头节点 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 解释:链表中没有环。
实现代码与解析:
快慢指针:
/**
* 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) {
ListNode* slow = head;
ListNode* fast = head;
// fast->next 这个条件,防止fast为空结点
while(slow && fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow) return true;
}
return false;
}
};
原理思路:
慢指针一次走一步,快指针一次走两步,若最后能相遇说明有环。
142. 环形链表 II
问题描述:
给定一个链表的头节点 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 解释:链表中没有环。
实现代码与解析:
快慢指针
/**
* 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* fast=head;//快指针
ListNode* slow=head;//慢指针
while(fast!=NULL&&fast->next!=NULL)
{
slow=slow->next;//慢指针每次走一步
fast=fast->next->next;//快指针每次走两步
if(slow==fast)
{
ListNode* index1=fast;//记录相遇位置
ListNode* index2=head;
//当快慢指针相遇时,两指针从head和相遇点同时出发,直至相遇,找到换的入口
while(index1!=index2)
{
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return NULL;//若无环
}
};
原理思路:
slow指针一次走一步,fast指针一次走两步。
其中n为fast指针在圈里转的圈数,根据算的结果可以看出,当n=1时,z=x,也就是说fast与slow相遇点到环的入口的长度等于x的长度,所以我们只要在头结点和相遇点定义index1,index2两个指针,一起移动,当其相遇的时候,就移动到了环的入口结点,直接返回即可。当然n不一定等于1,根据最后公式,只不过index2会在环里转几圈,最后还是会与index1在环入口相遇。
至于fast指针与slow指针为什么一定会相遇,而不是fast指针跳过slow指针呢?因为fast指针相对于slow指针一次是走一步,相当于物理里的相对运动吧,既然是走一步,那必然不会出现跳过的情况。
至于为什么slow指针不会在环里转超过一圈呢?因为fast指针一次走的是slow指针一次走的两倍,当slow走完一圈时,fast必然会走完两圈,所以在此之前两指针一定会相遇。
143. 重排链表
题目描述:
给定一个单链表 L
的头节点 head
,单链表 L
表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4] 输出:[1,4,2,3]
示例 2:
输入:head = [1,2,3,4,5] 输出:[1,5,2,4,3]
实现代码与解析:
线性表
/**
* 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:
void reorderList(ListNode* head) {
ListNode* cur = head;
vector<ListNode*> v;
while(cur)
{
v.push_back(cur);
cur = cur->next;
}
int l = 0, r = v.size() - 1;
while(l < r)
{
v[l]->next = v[r];
l++;
if (l == r) break;
v[r]->next = v[l];
r--;
}
v[l]->next = nullptr;
//重排后的链表,最后一个节点是原来链表中间的节点,其next不为空,我们需要手动将next设为空。
}
};
原理思路:
链表不能记录位置,我们用线性表存一下进行操作即可。