代码随想录Day | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II
两两交换链表中的节点
文档讲解:代码随想录
视频讲解: 帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点
状态:√
- 思路
和昨天的翻转链表差不多,对于一组节点来说,我们要做的就是,- 先保存第二个节点
- 将第一个节点指向第二个节点的后面那个节点
- 将第二个节点指向第一个节点
- 将头指针指向第二个节点
- 移动头指针,到下一组节点之前的那个节点上,也就是上一组反转之后的第二个节点,因为我们采用的虚拟头结点的方式
代码如下
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* First = new ListNode(0,head);
ListNode* cur = First;
ListNode* temp;
while(cur->next&&cur->next->next)
{
//记录第二个节点
temp = cur->next->next;
//将第一个节点的指向指向第二个节点的下一个节点
cur->next->next = temp->next;
//将第二个节点的指向指向第一个节点
temp->next = cur->next;
//将虚拟头结点的指向指向第二个节点
cur->next = temp;
//移动头结点到下一次调转列表之前
cur = cur->next->next;
temp = nullptr;
}
delete temp;
return First->next;
}
};
删除链表的倒数第N个节点
文档讲解:代码随想录
视频讲解: 链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点
状态:√
- 思路
倒数第n个就是翻转链表后正数第n个,所以考虑先翻转链表,然后定义一个头结点,找到第n个之前的那个节点,将其指向改变就可以删除了。
需要注意的是,下标从0开始,为了找到第n个节点,所以循环的判断应该是n-1。
代码如下
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode* cur = head;
ListNode* res = nullptr;
ListNode* temp;
while(cur)
{
temp = cur->next;
cur->next = res;
res = cur;
cur = temp;
}
delete temp;
return res;
}
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* resList = reverseList(head);
ListNode* First = new ListNode(0,resList);
ListNode* cur = First;
while(n-1)
{
cur = cur->next;
n--;
}
if(cur->next)
{
cur->next = cur->next->next;
}
ListNode* resB = reverseList(First->next);
return resB;
}
};
- 双指针
不用翻转链表,用双指针,由快指针先移动n+1步,然后两指针同时移动,当快指针指向的值为空时,慢指针刚好到达要删除的前一位。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* First = new ListNode(0,head);
ListNode* fast =First;
ListNode* slow = fast;
while(n+1)
{
fast = fast->next;
n--;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return First->next;
}
};
链表相交
文档讲解:代码随想录
视频讲解:
状态:√
- 思路
本题,主要就是两个链表的长度不一致,导致在移动的过程中,会错开找不到相交点,所以需要先将两个链表的长度变为一致,这里来的长度一致,是指从头结点到相交节点的长度一致。剩下的就是利用循环去寻找相等的点了。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int a = 0;
int lengthA = 0;
int lengthB = 0;
ListNode* calA = headA;
ListNode* calB = headB;
while(calA)
{
calA = calA->next;
lengthA++;
}
while(calB)
{
calB = calB->next;
lengthB++;
}
if(lengthA>lengthB)
{
while(lengthA-lengthB)
{
headA = headA->next;
lengthA--;
}
}
else
{
while(lengthB-lengthA)
{
headB = headB->next;
lengthB--;
}
}
while(headA&&headB)
{
if(headA == headB)
{
a = 1;;
break;
}
else
{
headA =headA->next;
headB =headB->next;
}
}
if(a)
{
return headA;
}
else
{
return NULL;
}
}
};
文档里面利用了swap将长的链表全部变为A链表,可以省去一个循环。
if(lengthA < lengthB)
{
swap(headA,headB);
swap(lengthA,lengthB);
}
时间复杂度: O ( m + n ) O(m+n) O(m+n)
- 双指针
详细解法参考力扣的题解
有两链表在交点之前的长度分别为a,b,相交之后的长度为c,第一次扫描链表两链表扫描指针走过的长度分别为a+c和b+c。当两链表的扫描指针到达尾端的时候,将指针的指向分别改为指向对方链表的头节点。这样扫描指针再次到达相交节点的时候,两个扫描指针走过的长度为a+c+b和b+c+a。就可以求得了。
环形链表II
文档讲解: 代码随想录
视频讲解:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II
状态: 起点的求解原理
- 思路
本题分为两点- 是否有环:快慢指针,快指针一次走两格,慢指针一次走一格,如果两个指针能够相遇,那么说明有环。
- 求起点:我们假设环的起点和链表头节点之间距离是k,环的起点到相遇点是l,相遇点到环的起点是m。
那么有等式,在相遇的时候成立–慢指针路径的两倍等于快指针走过的路径,n表示环内循环
2 ∗ ( k + l ) = n ( l + m ) + l + k 2*(k+l) = n(l+m)+l+k 2∗(k+l)=n(l+m)+l+k
通过整理可以得到
k = m + ( n − 1 ) ( l + m ) k = m+(n-1)(l+m) k=m+(n−1)(l+m)
k表示头节点到起点的距离,m表示相遇点到起点的距离,说明如果我们从头节点和相遇点同时有指针移动,那么会在起点相遇。
- 为什么会寻找下面的等式:因为我们只直到头节点和相遇点的位置,所以要利用这两个位置
最终代码如下
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//快慢指针,快指针2倍速,慢指针正常,若相遇则有环
ListNode* fast = head;
ListNode* slow = head;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
//求环的起点,从相遇点出发一个指针正常,起点出发一个指针正常
ListNode* fastFind = slow;
ListNode* slowFind = head;
while(slowFind != fastFind)
{
slowFind = slowFind->next;
fastFind = fastFind->next;
}
return slowFind;
break;
}
}
return NULL;
}
};

被折叠的 条评论
为什么被折叠?



