题目一
给你一个链表的头节点 head ,判断链表中是否有环。
使用快慢指针,如果慢指针等于快指针,就说明是带环链表
链表的中间结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
// 奇数结点 与 偶数结点 两种情况
while(fast && fast->next){
//奇数结点:5
//1 2 3 4 5
//slow 1 2 3
//fast 1 3 5
//fast的next为NULL
slow = slow->next;
fast = fast->next->next;
//偶数结点:4
//1 2 3 4
//slow 1 2 3
//fast 1 3 NULL
//fast为NULL
if(slow == fast)
return true;
}
return false;
}
题目二
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* m = head;
struct ListNode* k = head;
while((k!=NULL)&&(k->next!=NULL))
{
m = m->next;
k = k->next->next;
if(m == k)//证明是带环链表
{
while(head!=m)//让头指针开始和慢指针开始走(相等时候就是入环的第一个结点)
{
m = m->next;
head = head->next;
}
return m;//或者head
}
}
return NULL;
}
扩展知识点
慢指针每次走一步,快指针每次走两步,那么一定可以追上吗?
一定可以追上
当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为N。每追击一次,它们之间的距离缩小一。
在追击过程中,它们之间的距离变化为:
N、N-1、N-2、......1、0(追上了)
慢指针每次走一步,快指针每次走三步,那么一定可以追上吗?
当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为M。每追击一次,它们之间的距离缩小二·。
M、M-2、M-4、......
如果M是偶数:...4、2、0(追上了)
如果M是奇数:...3、1、-1(-1表示fast走在了slow前面一个位置)
而距离为1表示(fast在slow的后一个位置上)
距离为-1表示开始了新一轮的追击(追击的距离为C-1)其中C是环的长度(周长)
判断(C-1是偶数还是奇数):
如果是偶数,那么在下一轮的追击上一定可以追上(0)
如果是奇数,那么在下一轮的追击上一定不可以追上(-1)
慢指针每次走一步,快指针每次走四步,那么一定可以追上吗?
当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为K。每追击一次,它们之间的距离缩小三。
K、K-3、K-6、...
如果K是三的倍数,那么就一定会相遇(K%3 == 0)
K、K-3、K-6、...、6、3、0
if (K%3 == 2)
K、K-3、K-6、...、8、5、2、-1(C-1)
if (K%3 == 1)
K、K-3、K-6、...、10、7、4、1、-2(C-2)
这只是一种特殊情况(并不是正确的规律)
结论:
一个指针从起点开始走(head),一个指针从相遇点开始走(meet),它们会在环的入口点相遇。
还可以使用相交链表的思想去解决问题2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode * testa = headA;
struct ListNode * testb = headB;
//先去计算一下两个链表的长度
int lena = 0;
int lenb = 0;
while(testa!=NULL){
testa = testa->next;
lena++;
}
while(testb!=NULL){
testb = testb->next;
lenb++;
}
int lensum = abs(lena-lenb);
struct ListNode * longnode = headA;
struct ListNode * smartnode = headB;
if(lena<lenb){
longnode = headB;
smartnode = headA;
}
while(lensum--){
longnode = longnode->next;
}
while(longnode != smartnode){
longnode = longnode->next;
smartnode = smartnode->next;
}
return longnode;
}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* m = head;
struct ListNode* k = head;
while((k!=NULL)&&(k->next!=NULL))
{
m = m->next;
k = k->next->next;
if(m == k)//证明是带环链表
{
struct ListNode* meet = m;
struct ListNode* newhead = meet->next;
meet->next = NULL;
//相交链表
//head
//newhead
int lena = 0;
int lenb = 0;
struct ListNode* testa = head;
struct ListNode* testb = newhead;
//记得这里要先去找test去遍历计数
while(testa!=NULL){
testa = testa->next;
lena++;
}
while(testb!=NULL){
testb = testb->next;
lenb++;
}
int slen = abs(lena-lenb);
struct ListNode* longnode = head;
struct ListNode* smartnode = newhead;
if(lena<lenb){
longnode = newhead;
smartnode = head;
}
while(slen--){
longnode = longnode->next;
}
while(longnode!=smartnode){
longnode = longnode->next;
smartnode = smartnode->next;
}
return longnode;
//或者使用接口函数就行
// return getIntersectionNode(head,newhead);
}
}
return NULL;
}