letcode 分类练习 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表II
两两交换链表中的节点
双指针法解决(slow fast),这里我们用first和second分别暂存一下第一个和第二个节点,可以大大避免出错的可能性
/**
* 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* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(-1);
dummyhead -> next = head;
ListNode* slow = dummyhead; ListNode* fast = dummyhead -> next;
if(!fast) return dummyhead -> next;
while(fast && fast -> next){
ListNode* post = fast -> next -> next;
ListNode* second = fast -> next;
ListNode* fisrt = slow -> next;
slow -> next = second;
second -> next = fisrt;
fisrt -> next = post;
slow = fisrt;
fast = post;
}
return dummyhead -> next;
}
};
删除链表的倒数第N个节点
快慢指针解决,我们用一个虚拟头结点来实现找倒数第一个节点的前驱,遍历while(n–)的时候初始化虚拟头结点即可以找到。
我们先让快节点走n次,然后快节点和慢节点同步走,快节点的下一个节点为空的时候(不然slow->next->next会报空指针异常)慢节点即就是我们要找的倒数第N个节点的前驱
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(-1);
dummyhead -> next = head;
ListNode* slow = dummyhead; ListNode* fast = dummyhead;
while(n--){
fast = fast -> next;
}
while(fast->next){
fast = fast -> next;
slow = slow -> next;
}
slow -> next = slow -> next -> next;
return dummyhead -> next;
}
};
链表相交
A跟B的路径我们让headA和headB都走一遍就可以找到交点了
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int countA = 1; int countB = 1;
ListNode* tmpA = headA; ListNode* tmpB = headB;
while(tmpA && tmpB){
if(tmpA == tmpB) return tmpA;
tmpA = tmpA -> next;
tmpB = tmpB -> next;
if(tmpA == NULL && countA){
tmpA = headB;
countA--;
}
if(tmpB == NULL && countB){
tmpB = headA;
countB--;
}
}
return NULL;
}
};
环形链表II
我们有快指针移动距离为
L
f
a
s
t
=
x
+
y
+
n
(
z
+
y
)
L_{fast} = x + y+n(z+y)
Lfast=x+y+n(z+y)
慢指针移动距离
L
s
l
o
w
=
x
+
y
L_{slow} = x + y
Lslow=x+y
又由于
L
f
a
s
t
=
2
L
s
l
o
w
⇒
x
+
y
+
n
(
z
+
y
)
=
2
(
x
+
y
)
⇒
x
=
n
(
z
+
y
)
−
y
L_{fast} = 2 L_{slow} \Rightarrow x + y+n(z+y) = 2(x+y)\Rightarrow x = n(z+y)-y
Lfast=2Lslow⇒x+y+n(z+y)=2(x+y)⇒x=n(z+y)−y
由于相遇的时候,自然肯定是快指针已经走了至少一圈了,所以
n
≥
1
n ≥1
n≥1
所以,我们有
x
=
(
n
−
1
)
(
z
+
y
)
+
z
n
=
1
时
,
x
=
z
x = (n-1)(z+y) + z \\n=1时,x=z
x=(n−1)(z+y)+zn=1时,x=z
这个时候我们发现,其实就是从头结点出发,然后另一个节点从相遇点出发,新的相遇点就是我们的入口处
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* dummyhead = new ListNode(-1);
dummyhead -> next = head;
ListNode* slow = dummyhead;
ListNode* fast = dummyhead;
ListNode* together = NULL;
// 快慢指针模版写法
while(fast && fast -> next){
fast = fast->next-> next;
slow = slow -> next;
if(slow == fast){
together = slow;
break;
}
}
if(!together) return NULL;
ListNode* cur = dummyhead;
while(cur!=together){
cur = cur -> next;
together = together -> next;
}
return cur;
}
};