LeetCode刷题——链表2
删除链表的倒数第 N 个结点
题目链接.
- 题意:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
- 思路:
- 遍历链表,得到链表长度,计算倒数第n个节点是正序的第几个节点,然后遍历删除该节点(暴力)。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode * dummy = new ListNode(-1);
dummy->next=head;
ListNode *p=dummy;
int l=0;
while(p->next){
l++;
p=p->next;
}
int t=l-n+1,t1=0;
ListNode *p1=dummy;
while(p1->next){
t1++;
if(t1==t) p1->next=p1->next->next;
else p1=p1->next;
}
return dummy->next;
}
};
- 快慢指针,设置虚拟头节点,两个指针初始指向虚拟节点,快指针先走n步,然后快慢指针再同时走,当快指针指向链表结尾时,慢指针指向倒数n+1个节点,然后删除倒数第n个节点,返回虚拟头节点的下一个节点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy=new ListNode(-1);
dummy->next=head;
ListNode* p=dummy;
ListNode* q=dummy;
for(int i=0;i<n;++i) p=p->next;
while(p->next){
p=p->next;
q=q->next;
}
q->next=q->next->next;
return dummy->next;
}
};
链表相交
题目链接.
- 题意:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
- 思路:
- (暴力)两个循环,循环比较b中的节点是否等于a中的节点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * a=headA;
while(a!=nullptr){
ListNode * b=headB;
while(b!=nullptr){
if(b==a) return a;
else b=b->next;
}
a=a->next;
}
return nullptr;
}
};
- (哈希表),将a中的节点放入哈希表中,循环b中的节点,看哈希表中是否存在。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * a=headA;
ListNode * b=headB;
unordered_set<ListNode *> h;
while(a){
h.insert(a);
a=a->next;
}
while(b){
if(h.find(b)!=h.end()) return b;
b=b->next;
}
return nullptr;
}
};
- (双指针)设链表A的长度为a,链表B的长度为b,A到相交结点的距离为c,B到相交节点的距离为d,显然可以得到两者相交链表的长度:
a - c = b - d
, 变换一下式子得到:a + d = b + c
。用一个指针从链表A出发,到末尾后就从B出发,用另一个指针从B出发,到末尾后从A出发,由于上面的公式,当前一个指针走了a+d
步数时,后一个指针走了b+c
,两步数相等,即走到了相交节点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * a=headA;
ListNode * b=headB;
while(a!=b){
if(a!=nullptr) a=a->next;
else a=headB;
if(b!=nullptr) b=b->next;
else b=headA;
}
return a;
}
};
环形链表 II
题目链接.
- 题意:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
- 思路:
- (哈希表),初始化一个指针p指向头节点,如果p不为空,循环。如果p不在哈希表中,加入哈希表,如果存在,返回p。然后令
p=p->next
,如果循环顺利结束,则链表无环,返回nullptr。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode *> h;
ListNode* p=head;
while(p){
if(h.find(p)!=h.end()) return p;
else h.insert(p);
p=p->next;
}
return nullptr;
}
};
- (快慢指针),快指针一次走两步,慢指针一次走一步。如果快指针能变成空指针,则链表无环。
假设环之前的长度为a
,环的长度为b
。快指针走的长度为f
,慢指针走的长度为s
,当两个指针第一次相遇时f=2s
。快指针比慢指针多走n个环的长度f=s+nb
。得:s=nb,f=2nb
.
我们需要得到的是环入口的位置,第一次相遇并不一定在环入口处。从头节点出发到达环入口的长度l
满足:l=a+nb
。s
距离l
差a
,将快指针重新指向头节点,且变为一次走一步,慢指针同样一次走一步,a步后,快慢指针同时到达环入口,得到答案。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode * fast=head;
ListNode * slow=head;
while(fast){
if(fast->next==nullptr) return nullptr;
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
fast=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
}
return nullptr;
}
};