24. 两两交换链表中的节点 - 力扣(LeetCode)
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
定义一个
cur指针,处理cur指向的节点之后的2个节点,完成互换。
while的判断是cur->next&&cur->next->next,也就是cur之后同时有两个节点,才需要互换,如果之后只有一个节点,没有其余节点跟它互换;如果之后没有节点,自然不用再互换。
在②指向①之前,需要保存③,否则链表无法前进,因此用p1、p2、p3分别记录三个节点的地址
dummy的next应该是p2
p2的next应该是p1
p1的next应该是p3
之后,应该让cur移动到p1,处理后续的③和④
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode(); //虚拟头节点
dummy->next = head;
ListNode* cur = dummy;
ListNode* p1 = dummy;
ListNode* p2 = dummy;
ListNode* p3 = dummy;
while(cur->next&&cur->next->next){ //后两个节点非空
//记录
p1 = cur->next;
p2 = p1->next;
p3 = p2->next;
//交换
cur->next = p2;
p2->next = p1;
p1->next = p3;
//前进
cur = p1;
}
return dummy->next;
}
};
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
给你一个链表,删除链表的倒数第
n个结点,并且返回链表的头结点。
fast停在尾节点
fast先走n步,根据循环条件while(fast->next),尾节点无法进入循环,因此循环结束,fast停留在尾节点。
此时slow差n步走到尾节点,也就是第倒数n+1个节点,此时slow->next = slow->next->next可以删除倒数第n个节点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
while(n--){
fast = fast->next;//fast相比slow提前走n步
}
while(fast->next){ //停在尾节点
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummy->next;
}
};
fast停在nullptr
差n步到nullptr,就是倒数第几个节点。
fast停在nullptr,希望slow相距n+1步赶上fast,因此让fast走n+1步。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
while(n--){
fast = fast->next;//fast相比slow提前走n步
}
fast = fast->next;//再走一步,就是n+1步
while(fast){ //停在nullptr
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummy->next;
}
};
160. 相交链表 - 力扣(LeetCode)
给你两个单链表的头节点
headA和headB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回null。图示两个链表在节点
c1开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
🌟链表相交,不是值相同,而是节点地址相同!
由于链表长度不一致,从头开始遍历时,即使相交,也可能不会同时访问同一节点。
末尾对齐
由于链表一旦相交,不可能再分裂,因此可以末尾对齐,再齐头并进访问
---(图片来自代码随想录)
\\待补充...
拼接获得等长链表
拼接两个链表,从头遍历,可以同时进入相交部分,原因如下:
假设相交之前,链表B相比A长了n节点,因此会晚n步开始从头遍历A,而A相比B短了n节,因此同时第二次进入相交部分。
---(图片来自双指针技巧秒杀七道链表题目 | labuladong 的算法笔记)
如图所示,遍历两个拼接链表的指针会同时访问相交的第一个节点,返回此节点即可
-
若链表不相交,会不会死循环?
-
不会,由于拼接链表等长,会同时访问空指针,因此会返回nullptr并退出循环
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* p1 = headA;
ListNode* p2 = headB;
while(p1!=p2){
p1 = (p1==nullptr? headB : p1->next);
p2 = (p2==nullptr? headA : p2->next);
}
return p1;
}
};
142. 环形链表 II - 力扣(LeetCode)
给定一个链表的头节点
head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。如果链表中有某个节点,可以通过连续跟踪
next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos是-1,则在该链表中没有环。注意:
pos不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
示例
输入: head = [3,2,0,-4], pos = 1
输出: 返回索引为 1 的链表节点
解释: 链表中有一个环,其尾部连接到第二个节点。
后续补上分析...
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast&&fast->next){
fast = fast->next->next;
slow = slow->next;
if(slow == fast){ //fast套圈slow
fast = head; //fast回到头节点
while(slow != fast){
fast = fast->next; //单步前进
slow = slow->next;
}
return slow;
}
}
return nullptr;
}
};
思考
while(fast->next && fast->next->next){
fast->next->next;
//fast->next 非空 则fast->next->next不会出现空指针异常(nullptr->next)
//说明fast连走两步不会出现异常
//同上,fast->next->next非空,则可以连走三步
//最后一次满足条件是倒数第三个节点,进入while后,fast移动到尾节点,并结束while循环
//循环判断没有fast,若fast一开始就为空,fast->next出现异常
}
while(fast && fast->next){
fast->next->next;
//fast非空 则fast->next不会出现空指针异常(nullptr->next)
//说明fast走一步不会出现异常
//同上,fast->next非空,则可以连走两步
//最后一次满足条件是倒数第二个节点,进入while后,fast移动到nullptr,并结束while循环
}