题目描述:
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
其中链表中会有重复的数字出现
方法1:哈希表
此方法首先创建一个哈希表,然后循环链表,并存放每次循环到的链表位置指针,存放之前查找链表中是否有该指针,没有则将此位置指针存入哈希表,如果有,则说明此链表是环形链表,返回true. 如果循环到的位置为空,则说明该链表不是环形链表,返回false.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct hashTable
{
struct ListNode* key;
UT_hash_handle hh;
}Hash;
bool hasCycle(struct ListNode *head) {
Hash* all=NULL;
struct ListNode *pre = head;
while(pre!=NULL)
{
Hash* cur=NULL;
HASH_FIND_PTR(all, &pre, cur);
if(cur==NULL)
{
cur = (Hash*)malloc(sizeof(Hash));
cur->key= pre;
HASH_ADD_PTR(all, key, cur);
pre = pre->next;
}
else
{
return true;
}
}
return false;
}
方法2:快慢指针
此方法只需要创建一个慢指针和快指针来记录当前访问到的结点。其中慢指针每次前进一个结点,快指针每次前进两个结点。如果是环形链表,慢指针和快指针最终会相遇,而非环形链表最终会指向空。
对于慢指针和快指针为何分别前进一个结点和两个结点,解释如下:
假设初始慢指针和快指针间隔距离为N,L-F=N,(L代表慢指针,F代表快指针)然后慢指针前进一个结点,快指针前进两个结点,此时两个指针间隔距离变为了 L+1-(F+2)=L-F-1=N-1; 然后下一步距离则会变为N-2,依次执行下去,最终两个指针会相遇。
bool hasCycle(struct ListNode *head) {
if(head==NULL || head->next==NULL)
{
return false;
}
struct ListNode *low = head;
struct ListNode *fast = head->next;
while(low!=NULL && fast!=NULL)
{
if(low==fast)
{
return true;
}
low = low->next;
if(fast->next==NULL)
{
return false;
}
fast = fast->next->next;
}
return false;
}