Day04|链表02:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、 面试题 02.07. 链表相交、142.环形链表II

24.两两交换链表中的节点

leetcode链接:https://leetcode.cn/problems/swap-nodes-in-pairs/

视频链接:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点 (opens new window)

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]

跟之前的翻转链表比较相似,关键点都是创建虚拟头节点、以及保存tmp指针:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;
        while(cur->next != nullptr && cur->next->next != nullptr){
            ListNode* tmp1 = cur->next;//1
            ListNode* tmp2 = cur->next->next->next;//3
            cur->next = cur->next->next;//第一步
            cur->next->next = tmp1;//第二步
            tmp1->next = tmp2;//第三步
            cur = cur->next->next;//移动cur
        }
        return dummy->next;
    }
};

Day04|链表02:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、 面试题 02.07. 链表相交、142.环形链表II_第1张图片

这里的while(cur->next != nullptr && cur->next->next != nullptr){ 看似是冗余的,只要next为空,next->next肯定是空的了,但这考虑了head就为NULL的情况以及防止访问next->next是空指针。

19.删除链表的倒数第n的节点

leetcode链接:力扣题目链接(opens new window)

视频链接:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点 (opens new window)

本题一刷的时候,只有暴力思路,比如先遍历一次链表求出长度,再正序删除第m-n个节点,很明显这不是最优解。后来看完视频后,二刷直接就有了思路,也很幸运的直接ac了。实质就是双指针那一套,快指针先走n步,然后快慢指针同时走,知道快指针到底,此时快指针走了m-n步,慢指针也走了m-n步,正好停在要删除节点的前面。

以下摘自代码随想录:

  • 定义fast指针和slow指针,初始值为虚拟头结点,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xybvPHv-1689493489043)(https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LZmXjEeJ-1689493489044)(https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B91.png)]

  • fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nIBp2wcF-1689493489044)(https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B92.png)]

  • fast和slow同时移动,直到fast指向末尾,如题:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyWw9jZI-1689493489045)(https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B93.png)]

  • 删除slow指向的下一个节点,如图:

Day04|链表02:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、 面试题 02.07. 链表相交、142.环形链表II_第2张图片

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* fast = dummy;
        ListNode* slow = dummy;
        while(n--){
            fast = fast->next;
        }
        while(fast->next != nullptr){
            fast = fast->next;
            slow = slow->next;
        }//结束后slow停在要删除节点的前一个位置
        // cout<< slow->next->val;
        ListNode* tmp = slow->next;
        slow->next = tmp->next;
        delete tmp;
        return dummy->next;

    }
};

面试题 02.07. 链表相交

leetcode链接:力扣题目链接(opens new window)

Day04|链表02:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、 面试题 02.07. 链表相交、142.环形链表II_第3张图片

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

这里的注意点是值相同不一定等于相交,应该是两个节点的指针相同。

这道题是一刷,只想到暴力解法,两个for循环,一个一个比较,后来看了题解才做出来。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lengthA = 0, lengthB = 0;
        while(curA != nullptr){
            lengthA++;
            curA = curA->next;
        }
        while(curB != nullptr){
            lengthB++;
            curB = curB->next;
        }
        //这里要重新开始遍历,要对curA curB进行重新赋值
        curA = headA;
        curB = headB;
        //假设A为短的链表,B为长的链表
        if(lengthA > lengthB){
            swap(lengthA,lengthB);
            swap(curA,curB);
        }
        int gap = lengthB - lengthA;
        while(gap--){
            curB = curB->next;
        }
        while(curA != nullptr){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;

    }
};

142.环形链表II

leetcode链接:力扣题目链接(opens new window)

视频链接:把环形链表讲清楚!| LeetCode:142.环形链表II (opens new window)

这题是二刷了, 当时一刷就云里雾里了,二刷首先想到了方法,知道怎么判断是否有环了,但怎么求环的入口还是转不过来。总结一下就是快慢指针,如果有环那么一定能相遇。重点是怎么求环的入口:

Day04|链表02:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、 面试题 02.07. 链表相交、142.环形链表II_第4张图片

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast != nullptr && fast->next != nullptr){
            fast = fast->next->next;
            slow = slow->next;
            if(fast == slow) {//说明有环
                slow = head;
                while(slow !=  fast){
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
            }
        return nullptr;
        }



};

总结

链表章节的题目刷完了,大部分二刷都有思路,但通过几次才能AC,总的来说难度不大,环形列表可能求入口的时候有点难以理解。

你可能感兴趣的:(链表,linux,数据结构)