一、题目描述
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
二、解题思路
一开始这题我想如果数据结构中对于结点的定义多加一个标注值的话,就很容易了,遍历一遍链表,遍历过的结点改变其标注值,如果遍历的结点其标注值是改变过的,那么这个链表一定是有环的。但是有一个问题是,力扣里面已经把结点的结构体写好了,因此就需要换一种办法,保存每一个遍历过的结点的值,然后在遍历结点之前,首先在数组里面找是否有重复的结点。这里有两个问题,一个是要申明动态数组,因为不知道结点有多少个(因为有可能是循环的),这个比较麻烦,另一个问题是每遍历一个结点,都要在数组中去找是否有相同的,时间复杂度,也很高。
在看了题解后,发现用unordered_set,即hash 表可以解决相应的问题。用unordered_set表申明一个哈希表,解决了动态生成数组的问题,用unordered_set中的count函数,可以解决查找相同值的问题,用unordered中的insert函数可以解决插入表的问题。
具体代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> search;
while(head){
if(search.count(head))
return true;
search.insert(head);
head=head->next;
}
return false;
}
};
三、分析
这里用了辅助hash表,其空间复杂度为O(n),这题的思路还有快慢指针也可以解决。
快慢指针是当快慢指针进入循环时,肯定会最后相遇。所以快慢指针在处理追击问题是比较好用的,空间复杂度低,只要O(1)就好。下面是快慢指针的代码。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(!head||!head->next)
return false;
ListNode* fast=head->next;
ListNode* slow=head;
while(fast!=NULL&&fast->next!=NULL){
if(fast==slow){
return true;
}
fast=fast->next->next;
slow=slow->next;
}
return false;
}
};