代码随想录算法训练营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

posted @   coder小杰  阅读(275)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示