文章目录
- 题目
 - 题目链接
 - 题目要求
 
- 解题思路
 - 方法一:哈希表
 - 方法二:双指针
 
- 进阶思考
 - 快指针一次走三步
 
- 进阶问题(入口点)
 - 题目链接
 - 题目要求
 - 问题思路
 
- 总结
 
题目
题目链接
环形链表
题目要求

解题思路
显而易见的是,单纯的遍历循环是肯定不行的,既然是循环,关键就是要找到重复的地址,用值判断不行的,可能有重复的值。
方法一:哈希表
1,用哈希表储存节点指针的值,找到重复的则返回TRUE。
class Solution {
public:
    bool HasCycle(ListNode *head) 
    {
        unordered_set<ListNode*> hashtable; //哈希表
        while (head != nullptr) 
        {
            if (hashtable.count(head)) 
            {
            	//如果当前节点已经有存储,则说明有重复
                return true;
            }
            //插入节点
            hashtable.insert(head);
            head = head->next;
        }
        return false;
    }
};
 
方法二:双指针
1,即使不会哈希表也没关系,用常见的快慢指针也可以解题。
2,不是循环链表:快指针会到达空节点,直接返回false即可。
 3, 是循环链表:快指针先进入环中,变成追击问题,画图如下。

 4,追击过程中,距离变化:(快指针一次两步,慢指针一次一步)

 代码实现:
bool hasCycle(struct ListNode *head) {
    if(head == NULL||head->next == NULL) return false;
    struct ListNode *slow = head;
    struct ListNode *fast = head->next;
    while(fast!=NULL && fast->next!=NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)
        {
            return true;
        }
    }
    return false;
}
 
进阶思考
快指针一次走三步
1,快指针相当于每次追击两步,要分情况讨论初始距离的情况。
如下:

 2,可以看出,当N为偶数时是可以追上的,当N为奇数则分情况。
- 距离为-1时,实际距离是C-1(C为环的长度)
 
如图:

 3,可以看出,C为奇数时可以达成,为偶数则不行。
4,更多的步数则是以此类推。
进阶问题(入口点)
题目链接
环形链表入口
题目要求

问题思路
1,显而易见,第一个重复的节点就是入口节点,可以用哈希表判断,直接返回第一个节点。
代码:
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> visited;
        while (head != nullptr) {
            if (visited.count(head)) {
                return head;
            }
            visited.insert(head);
            head = head->next;
        }
        return nullptr;
    }
};
 
2,快慢指针,经过前面的推论我们可以进一步推导得到如下:

3,如此可知,M为1的时候, 一个指针从相遇点走,一个从起点走,最终在入口点相遇。
代码实现:
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;
    }
};
 
总结
做这种题需要假设举例,一定的数学推导,从例子中找出其中的普遍规律,才能快速解题。



















