Day4| 24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点, 面试题 02.07. 链表相交, 142.环形链表II
两两交换链表中的节点
LeetCode题目链接:https://leetcode.cn/problems/remove-linked-list-elements/
解题思路
先看题目,因为是要两两进行交换,所以与直接翻转有所不同。需要考虑更多的情况,比如头结点的更换问题。为了避免特殊处理,添加虚拟头结点。之后,因为两两反转后,指向第三个节点的部分也出现了改变,因此第三个节点也需要用额外的临时变量进行存储。
因此,首先初始化一个虚拟头结点来作为当前的头结点,再补充一个临时变量,进行迭代。
代码如下:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL){
return head;
}
ListNode *dummyHead = new ListNode(0,head);
ListNode *front = dummyHead;
ListNode *pred =head;
ListNode *temp;
while(front->next!=NULL&&front->next->next!=NULL){
temp = pred->next->next;
pred->next->next = pred;
front->next = pred->next;
pred->next = temp;
front = pred;
pred = front->next;
}
return dummyHead->next;
}
};
删除链表的倒数第N个节点
LeetCode题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list
解题思路
删去倒数第n个元素,那么首先要知道整个链表的长度,在已知链表长度的基础上,可以得出倒数第n个值是正数的第几个节点。
此后,设置一个节点用于到达该位置,另一个节点集合该位置之前的点。便完成了删除节点的操作。
具体代码如下:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummyHead = new ListNode(0,head);
ListNode *current = head;
ListNode *front = dummyHead;
int size = 0;
while(current!=NULL){
current = current->next;
size++;
}
current = head;
for(int i=0;i<size-n;i++){
current = current->next;
front = front->next;
}
front->next = current->next;
return dummyHead->next;
}
};
链表相交
LeetCode题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
解题思路
需要判定两个链表的相交部分,主要需要保持两个链表的节点更新始终保持到尾部的距离相同。这样才能同步去判定节点位置是否相交。但是因为两个链表长度不定,因此需要先计算出链表的长度。再使长度不等的链表中较长的链表去除头部元素,使其到尾部节点的距离相同,再进行迭代,就可以轻松判定出是否相交了。
具体代码如下:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* currentA = headA;
ListNode* currentB = headB;
int sizeA=0,sizeB=0;
while(currentA!=NULL){
currentA = currentA->next;
sizeA++;
}
while(currentB!=NULL){
currentB = currentB->next;
sizeB++;
}
currentA = headA;
currentB = headB;
if(sizeA<sizeB){
swap(sizeA,sizeB);
swap(currentA,currentB);
}
int dif = sizeA-sizeB;
for(int i=0;i<dif;i++){
currentA = currentA->next;
}
while(currentA!=NULL){
if(currentA==currentB){
return currentA;
}
currentA = currentA->next;
currentB = currentB->next;
}
return NULL;
}
};
环形链表II
LeetCode题目链接:https://leetcode.cn/problems/linked-list-cycle-ii
解题思路
先看题目,首先需要判断链表是否有环,因此可以进行判断,一旦指针在迭代时出现->next=NULL则说明不存在环形,跳出循环并返回NULL。
之后进行环形判断,当链表存在环形,易得快慢指针一定存在交点。假设从链表起点到环形起点的距离为 x x x,环形起点到交点的距离为 y y y,交点到环形起点的距离为 z z z。可以得到以下公式:
当快慢指针相遇时有,其中
(
x
+
y
)
(x+y)
(x+y)为慢指针的移动距离,由于快指针是慢指针的二倍,所以乘以2后等式成立:
2
(
x
+
y
)
=
x
+
y
+
n
∗
(
y
+
z
)
2(x + y) = x +y +n*(y+z)
2(x+y)=x+y+n∗(y+z)
化简可以得到:
x
+
y
=
n
∗
(
y
+
z
)
x+y = n*(y+z)
x+y=n∗(y+z)
即可以求得链表起点到环形起点的距离公式,如果得到
x
x
x即可得出环形的起点位置:
x
=
(
n
−
1
)
∗
(
y
+
z
)
+
z
x = (n-1)*(y+z) + z
x=(n−1)∗(y+z)+z
同时,可以观察到 y + z y+z y+z为一个环形,因此可以看作:从交点位置出发,与从链表头出发,一定会在环形的起点处相遇。
代码如下:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head;
ListNode *slow = head;
while(fast!=NULL&&fast->next!=NULL){
fast = fast->next->next;
slow = slow->next;
if(slow==fast){
ListNode * index1=head;
ListNode * index2=slow;
while(index1!=index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};