【环型链表】快慢指针解决链表问题

作者:Time-Limit
链接:https://leetcode.cn/problems/linked-list-cycle/solution/yi-wen-gao-ding-chang-jian-de-lian-biao-wen-ti-h-2/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
本文摘选自此文,感谢作者

无法高效获取长度,无法根据偏移快速访问元素,是链表的两个劣势。然而面试的时候经常碰见诸如获取倒数第k个元素,获取中间位置的元素,判断链表是否存在环,判断环的长度等和长度与位置有关的问题。这些问题都可以通过灵活运用双指针来解决。

倒数第k个元素的问题

设有两个指针 p 和 q,初始时均指向头结点。首先,先让 p 沿着 next 移动 k 次。此时,p 指向第 k+1个结点,q 指向头节点,两个指针的距离为 k 。然后,同时移动 p 和 q,直到 p 指向空,此时 q 即指向倒数第 k 个结点。可以参考下图来理解:
【环型链表】快慢指针解决链表问题_第1张图片

获取链表中间元素

获取中间元素的问题。设有两个指针 fast 和 slow,初始时指向头节点。每次移动时,fast向后走两次,slow向后走一次,直到 fast 无法向后走两次。这使得在每轮移动之后。fast 和 slow 的距离就会增加一。设链表有 n 个元素,那么最多移动 n/2 轮。当 n 为奇数时,slow 恰好指向中间结点,当 n 为 偶数时,slow 恰好指向中间两个结点的靠前一个(可以考虑下如何使其指向后一个结点呢?
【环型链表】快慢指针解决链表问题_第2张图片

是否存在环 LC141

【环型链表】快慢指针解决链表问题_第3张图片上一部分中,总结快慢指针的特性 —— 每轮移动之后两者的距离会加一。下面会继续用该特性解决环的问题。
当一个链表有环时,快慢指针都会陷入环中进行无限次移动,然后变成了追及问题。想象一下在操场跑步的场景,只要一直跑下去,快的总会追上慢的。当两个指针都进入环后,每轮移动使得慢指针到快指针的距离增加一,同时快指针到慢指针的距离也减少一,只要一直移动下去,快指针总会追上慢指针。

是否存在环并找到环的第一个节点 LC142

【环型链表】快慢指针解决链表问题_第4张图片本题相对只是判断环要复杂很多。
最简单的方法是哈希,哈希中存每个节点的地址,遇到重复就碰到了环的第一个节点。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode*> nodeSet;
        ListNode* node = head;
        while(node != nullptr){
             if (nodeSet.count(node) == 0){
                 nodeSet.insert(node);
                 node = node->next;
             } else {
                 return node;
             }
        }
        return nullptr;
    }
};

更好的方法还是双指针,但是要经过一些计算:
【环型链表】快慢指针解决链表问题_第5张图片【环型链表】快慢指针解决链表问题_第6张图片
难点在于先进行一波计算,算出a的表达式之后,要意识到ptr和slow的关系。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head, *fast = head;
        while (fast != nullptr) {
            slow = slow->next;
            if (fast->next == nullptr) {
                return nullptr;
            }
            fast = fast->next->next;
            if (fast == slow) {
                ListNode *ptr = head;
                while (ptr != slow) {
                    ptr = ptr->next;
                    slow = slow->next;
                }
                return ptr;
            }
        }
        return nullptr;
    }
};

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