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

学习记录,主要参考:代码随想录

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

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/description/
文章讲解:https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
视频讲解:https://www.bilibili.com/video/BV1YT411g7br/?spm_id_from=333.788&vd_source=e70917aa6392827d1ccc8d85e19e8375
实现情况:
切记本题不能修改节点内部的值
思路 使用虚拟头节点,然后如果需要置换位置的处理情况一样
1、记录后面节点
2、交换节点
3、移动指针
4、循环前面步骤
5、结束条件是后面没有需要操作的两个节点了

/**
 * 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* dummy_head = new ListNode(0);
        dummy_head->next = head;
        ListNode* cur = dummy_head;

        while (cur->next && cur->next->next != nullptr) {//确保后面还有两个节点可以进行交换
            ListNode* tmp = cur->next->next->next;//记录当前循环不需要处理的节点信息
            ListNode* tmp1 = cur->next;//记录需要删除节点
            cur->next = cur->next->next;//相当于删除中间的节点
            cur->next->next = tmp1;//将删除的节点补到后面
            cur->next->next->next = tmp;//恢复全部链表
            cur = cur->next->next;//将cur指针移动到下一个“虚节点”位置,方便后续的处理
        }
        head = dummy_head->next;
        delete dummy_head;
        return head;
    }
};

在这里插入图片描述

9.删除链表的倒数第N个节点

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/
文章讲解:https://programmercarl.com/0019.%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.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf/?spm_id_from=333.788&vd_source=e70917aa6392827d1ccc8d85e19e8375
实现情况:
这里不需要判断n值的有效性?
实现思路,双指针
1、快指针先移动n 个位置,fast指针不能为空
2、fast指针需要提前走一步
3、两个指针同时移动,fast指针不能为空
3、删除slow指针指向的下一个节点

在这里插入图片描述

/**
 * 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(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while (n--&& fast != NULL) {//确保fast指针有效
            fast = fast->next;
        }  fast = fast->next;//fast需要提前走一步
        while (fast != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* tmp = slow->next;
        slow->next =slow->next->next;
        delete tmp;
        return dummyHead->next;
    }
};

面试题 02.07. 链表相交

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
文章讲解:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html

实现情况:
实现思路
1 计算两个链表的长度
2 确保B是长的链表
3 计算长度差值
4 比较A和B是否有相同的元素 有返回

if (curA == curB):
// if (curA->val == curB->val) {

这是一个指针比较。它检查curA和curB是否指向内存中的同一个位置,即它们是否引用同一个ListNode对象。这种比较通常用于检查两个链表是否在某个节点上相遇(例如,在检测两个链表是否相交时)。
如果curA和curB指向同一个节点,那么curA == curB的结果为true;否则为false。
指针比较不关心节点中存储的值,只关心指针本身。
// if (curA->val == curB->val)(注释掉的代码):
这是一个值比较。它检查curA和curB所指向的节点的值是否相等。这里假设curA和curB都不是nullptr,因为解引用nullptr会导致运行时错误。
如果curA和curB所指向的节点的值相等,那么curA->val == curB->val的结果为true;否则为false。
值比较关注节点中存储的具体数据,而不是节点本身在内存中的位置。

    if (lenB < lenA) {
        swap(lenA, lenB);
        swap(curA, curB);
    }

这段代码的目的是在处理两个链表(假设为链表A和链表B,分别由curA和curB指向它们的头节点)时,确保链表A的长度不小于链表B的长度,并且curA指向较长的链表,curB指向较短的链表。这是通过比较两个链表的长度(lenA和lenB)来实现的,并在必要时交换它们。

/**
 * 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* curA = headA;
        ListNode* curB = headB;
        // 1 计算两个链表的长度
        int lenA = 0;
        while (curA != NULL) {
            curA = curA->next;
            lenA++;
        }
        int lenB = 0;
        while (curB != NULL) {
            curB = curB->next;
            lenB++;
        }

        // 2 确保B是长的链表
        if (lenB < lenA) {
            swap(lenA, lenB);
            // swap(curA, curB);
            swap(headA, headB);
        }
   
        // 3 计算长度差值
        int gap = lenB - lenA;
        curA = headA;
        curB = headB;
        while (gap--) {
            curB = curB->next;
        }

        // 4 比较A和B是否有相同的元素 有返回
        while (curB != NULL) {
            // if (curA->val == curB->val) {
            if (curA == curB) {
                return curB;
            }
            curB = curB->next;
            curA = curA->next;
        }
        return NULL;
    }
};

在这里插入图片描述

142.环形链表II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/
文章讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob/?spm_id_from=333.788&vd_source=e70917aa6392827d1ccc8d85e19e8375

实现思路:
一开始想到了双指针,但是怎么计算环的入口没有想清楚!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* detectCycle(ListNode* head) {

        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next;
            fast = fast->next;
            slow = slow->next;
            if (fast == slow) {//快慢指针相遇了
                ListNode* index1 = slow;//现在这个节点一定在环内
                ListNode* index2 = head;

                while (index1 != index2) {//他们在入口处相遇了!!!
                    index1 = index1->next;
                    index2 = index2->next;
                }

                return index2;
            }

        }
        return NULL;
    }
};

在这里插入图片描述

总结

链表的种类主要为:单链表,双链表,循环链表
链表的存储方式:链表的节点在内存中是分散存储的,通过指针连在一起。
链表的基本操作包括建立链表、插入节点、删除节点、查找节点等。这些操作通常通过遍历链表并修改节点的指针域来实现。
经典题目:
203.移除链表元素:学会使用虚拟头结点
707.设计链表:学会链表的基本操作、获取第n个元素、头部插入、尾部插入、第n个节点前插入、删除第n个节点;统一使用虚拟头结点,操作便捷
19.删除链表的倒数第N个节点:虚拟头节点+双指针+窗口概念解决
206.反转链表:使用双指针解决
24. 两两交换链表中的节点:添加虚拟头节点后续统一操作,注意判断条件,要满足虚拟头结点后面有两个节点可以进行交换
面试题 02.07. 链表相交 :注意节点数值相等不是节点等价!!!
142.环形链表II:需要好好思考一下

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

li星野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值