代码随想录算法训练营day4 | 24.两两交换链表中的节点、19.删除链表的倒数第N个节点、160.相交链表、142.环形链表Ⅱ
24.两两交换链表中的节点
点击查看代码
/**
* 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) {
//有完整的一对,即两个链表节点才交换
if(head == nullptr || head->next == nullptr) return head;
ListNode *dummyhead = new ListNode(-1, head);
ListNode *zero = dummyhead; //指向虚拟头节点
ListNode *first = head; //指向第一个节点
ListNode *second = head->next; //指向第二个节点
while(1) {
zero->next = second; //步骤一
first->next = second->next; //步骤三
second->next = first; //步骤二
//有完整的一对,即两个链表节点才交换
if(first->next == nullptr || first->next->next == nullptr) break;
zero = first; //相当于新的虚拟头节点
first = zero->next; //下一组中的第一个节点
second = first->next; //下一组中的第二个节点
}
head = dummyhead->next;
delete dummyhead;
return head;
}
};
将虚拟头节点、待交换的第一个节点、待交换的第二个节点视为一组,分别进行步骤一、步骤三、步骤二,然后判断下一轮是否有完整的一对,即两个可交换的链表节点,若有,则更新三个指针,分别指向新的虚拟头节点、待交换的第一个节点、待交换的第二个节点,然后进行重复操作
19.删除链表的倒数第N个节点
点击查看代码
/**
* 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* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummyhead = new ListNode(-1, head);
ListNode *slow = dummyhead, *fast = dummyhead;
int count = 0;
while(count++ < n+1) fast = fast->next;
while(fast) {
slow = slow->next;
fast = fast->next;
}
ListNode *q = slow->next;
slow->next = q->next;
delete q;
head = dummyhead->next;
delete dummyhead;
return head;
}
};
核心思路:fast指针先走n+1步(注意,不是n,而是n+1,因为要找到倒数第n个节点的前驱节点),然后slow指针和fast指针一起往前走,直到fast指针走到nullptr,此时slow指针所指即为倒数第n个节点的前驱节点
本题所给提示中,1 <= n <= size,故不会出现n非法的情形,无需作特殊处理,一趟扫描即可完成。
160.相交链表
解法一:
点击查看代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p_A = headA, *p_B = headB;
int size_A = 0, size_B = 0;
while(p_A) { //求A链表长度
++size_A;
p_A = p_A->next;
}
while(p_B) { //求B链表长度
++size_B;
p_B = p_B->next;
}
int count = abs(size_B - size_A); //求A、B链表长度差
p_A = headA, p_B = headB;
while(count-- > 0) { //长链表的指针先走count步,走完后长短链表指针一起走
if(size_A > size_B) p_A = p_A->next;
else p_B = p_B->next;
}
while(p_A) { //长短链表指针一起走,若有相交节点,必能同时到达相交节点处
if(p_A == p_B) return p_A;
p_A = p_A->next;
p_B = p_B->next;
}
return nullptr; //前面都没返回,说明没有相交节点
}
};
点击查看代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p_A = headA, *p_B = headB;
int count_A = 0, count_B = 0;
while(p_A && p_B) {
if(p_A == p_B) return p_A;
if(p_A->next == nullptr) {
if(count_A == 0){
p_A = headB;
++count_A;
}
else return nullptr;
}
else p_A = p_A->next;
if(p_B->next == nullptr) {
if(count_B == 0){
p_B = headA;
++count_B;
}
else return nullptr;
}
else p_B = p_B->next;
}
return nullptr;
}
};
解法二核心思想:p_A走完A链表后走B链表,p_B走完B链表后走A链表,若有相交节点,必然能同时到达相交节点处,若无相交节点,二者必然同时第二次遇到nullptr,故需要count_A和count_B分别记录p_A和p_B是第几次遇到nullptr,count = 0时为第一次遇到,切换另一个链表遍历,若count = 1则为第二次遇到,此时说明必然无相交节点,直接返回nullptr
142.环形链表Ⅱ
有点懵,后续解决...
2025/02/16
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性