代码随想录 day04

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

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0, head);
        ListNode* cur = dummyHead; // 使用虚拟头节点,可以统一操作所有节点
        ListNode* temp01;
        ListNode* temp02;

        // 注意事项:
        // 此处的判断条件中,先判断当前节点的 next 是否为空,之后判断 当前节点的下一个节点的 next 是否为空
        // 这样处理的原因是为了避免操作空指针引发异常
        while (cur->next != nullptr && cur->next->next != nullptr) {
            // 例如:链表为 dummyHead---> 1 ---> 2 ---> 3 --- > 4 ---> nullptr
            temp01 = cur->next;             // 保存数值为 1 的节点的地址
            temp02 = cur->next->next->next; // 保存数值为 3 的节点的地址
            cur->next = cur->next->next;    // 将 dummyHead 指向数值为 2 的节点
            cur->next->next = temp01;       // 将数值为 2 的节点指向数值为 1 的节点
            temp01->next = temp02;          // 将数值为 1 的节点指向数值为 3 的节点

            cur = cur->next->next;          // cur 向右移动两个位置
        }
        return dummyHead->next;             // 返回新链表的头节点
    }
};

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

解法 1:

// a + b + c = b + c + a
// 若无交集,则 a + b = b + a
// 设交集长度为 c,去掉交集后短的长度为 a,长的长度为 b
// 则短链长度 a +c
// 则长链子长度 b +c
// b > a
// 第一轮可以让他们两个都移动 a + c 步
// 短链剩下长度 0
// 长链剩下长度 b - a
// 之后短链赋值为长链头节点
// 则之前的短链长度为 b + c
// 长链子长度为 b - a (长链子走到头会赋值短链提前说一下)
// 此时走 b 的长度
// 短链则为 b + c - b = c 正好是相交的头节点
// 长链子走 b 则为 b - a - b = -a 可知我们肯定是赋值了短链长度 a + c,又因为前面是 -a 故
// a + c - a = c 此时也是相交的头节点可以返回,代码实现如下,纯数学方法证明

// 思路:
// 两个指针分别从两个链表的头节点开始,遍历链表
// 当有其中一个链表为空时,将其指向另一个链表的头节点,否则指向本链表的下一个节点
// 不断循环,直到两个指针都为空时,说明两个链表没能相交
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA; // 指向链表 A 的头节点
        ListNode* curB = headB; // 指向链表 B 的头节点

        while (curA != curB) { // 不断循环,直到两个指针都为空时,说明两个链表没有相交
            if (curA == nullptr) { // 如果其中指针为空时,将其指向另一个链表的头节点
                curA = headB;
            } else {
                curA = curA->next; // 否则指向本链表的下一个节点
            }

            if (curB == nullptr) { // 同理
                curB = headA;
            } else {
                curB = curB->next;
            }
        }
        // 此处返回 curA 与 curB 效果相同
        return curA;
    }
};

解法 2:

// 步骤:
// 1. 先计算出两个链表的长度
// 2. 计算出两个链表的长度差值
// 3. 较长链表先移动差值个节点
// 4. 两个链表从同位置的节点同时开始移动比较地址是否相同
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;

        int lenA = 0;
        int lenB = 0;

        // 1. 计算两个链表的长度
        while (curA != nullptr) {
            curA = curA->next;
            lenA++;
        }
        while (curB != nullptr) {
            curB = curB->next;
            lenB++;
        }

        // 2.计算出两个链表的差值
        int distance = 0;
        ListNode* fast = nullptr;
        ListNode* slow = nullptr;
        if (lenA > lenB) {
            distance = lenA - lenB;
            fast = headA;
            slow = headB;
        } else {
            distance = lenB - lenA;
            fast = headB;
            slow = headA;
        }

        // 3.较长链表先移动差值个节点
        while (distance > 0) {
            distance--;
            fast = fast->next;
        }

        // 4.两个链表从相同位置的节点开始同时移动,比较地址是否相同
        while (fast != nullptr) {
            if (fast == slow) { 
                return fast;
            }
            fast = fast->next;
            slow = slow->next;
        }
        return nullptr; // 循环完毕,没有发现相交
    }
};

142.环形链表II

// 思路:
// 首先判断是否存在环
// 之后找到环的入口

// 步骤:
// 1. 使用 fast 与 slow 指向链表的头节点
// 使 fast 一次移动两个节点的位置,slow 一次移动一个节点的位置,判断两个节点是否相交

// 2. 在相交处定义一个背后指针 index01,在链表头节点处定义一个指针 index02
// 使两个新指针从相交位置开始一次移动一个节点的位置,当再次相交的时,该位置就是环的入口
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 使用 fast 与 slow 指向两个链表的头节点
        ListNode* fast = head;
        ListNode* slow = head;

        // 判断两个节点是否相交
        // fast->next != nullptr 表明链表不存在环
        while (fast != nullptr && fast->next != nullptr) {
            fast = fast->next->next; // fast 一次移动两个节点的位置
            slow = slow->next;       // slow 一次移动一个节点的位置

            // 是否存在环
            if (fast == slow) {
                ListNode* index01 = fast;
                ListNode* index02 = head;

                // 找出环的入口
                while (index01 != index02) {
                    index01 = index01->next;
                    index02 = index02->next;
                }
                return index01;
            }
        }
        return nullptr;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值