环形链表II
没思路,甚至想先看一下能不能算出size,但是应该会直接死循环
法一:
遍历一个元素就存一个在vector里,并且每次都查询这个元素的指针和vecor里的历史指针有没有相等的
/**
* 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) {
vector<ListNode*> num;
if (head == nullptr) {
return nullptr;
}
ListNode* p = head;
while (p != nullptr) {
num.push_back(p);
for (ListNode* q : num) {//vector遍历
if(p->next == q){//
return q;
}
}
p = p->next;
}
return nullptr;
}
};
法二:强数学推理
挺抽象的
fast和slow速度比2:1,时间相同,距离【x+y+n(y+z)】 : (x+y)
为什么是(x+y)呢,即为什么slow一定不会转1圈以上再相遇呢:【这很重要,因为n不是fast和slow的路程差,而是实际路程,因为这是在算比例】
-->【slow在环入口时,fast在环入口任意位置(不考虑就在环入口这个特殊情况),这里假设在位置k处。
可以自己画一个圈,在此刻,相当于fast追slow,从物理意义将,fast位移x1是个负值,x1 = -k;slow的位移x2 = 0 ;
若slow走了一圈即x1=n; x2 = 2n-k;
可以自己画一个x-t图,会发现会相交的。】
得:2(x+y ) = x+y+n(y+z)
x = (n-1)(y+z)+z,结合上图,即一个指针从head走,一个从fast和slow相交点走,相同速度总会相遇。
代码:注意while(p!=nullptr && p->next!=nullptr),因为p是快的指针,所以while里不用考虑q,涉及到p->next->next,所以涉及p->next;
链表只有头结点的情况没有考虑,所以p!=nullptr,避免p->next出现问题(可以考虑用虚拟指针)
/**
* 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) {
if(head == nullptr){
return nullptr;
}
ListNode *p,*q;//p快
p = q =head;
int tag = 0;
while(p!=nullptr && p->next!=nullptr){//p!=nullptr && p->next!=nullptr
p=p->next->next;
q = q->next;
if(p==q){
tag = 1;
break;
}
}
if(tag == 0){
return nullptr;
}
p = head;
while(p!=q){
p = p->next;
q = q->next;
}
return p;
}
};
快慢指针(双指针)用法总结
翻转链表
删除链表的倒数第N个节点
链表相交