文章目录
- 题目
- 题目链接
- 题目要求
- 解题思路
- 方法一:哈希表
- 方法二:双指针
- 进阶思考
- 快指针一次走三步
- 进阶问题(入口点)
- 题目链接
- 题目要求
- 问题思路
- 总结
题目
题目链接
环形链表
题目要求
解题思路
显而易见的是,单纯的遍历循环是肯定不行的,既然是循环,关键就是要找到重复的地址,用值判断不行的,可能有重复的值。
方法一:哈希表
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;
}
};
总结
做这种题需要假设举例,一定的数学推导,从例子中找出其中的普遍规律,才能快速解题。