题目描述
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
code
- 通过修改链表
- 时间复杂度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)
return 0;
ListNode *p = head;
int reset = 0x7f7f7f;
while(p&&p->val!=reset){//判断p是否为NULL要写在前面
p->val = reset;
p = p->next;
}
return p ? 1 : 0;
}
};
- 不修改链表
- 使用快慢指针:快指针每次前进2步,慢指针每次前进1步
- 链表存在环时快慢指针一定会相遇?
是的。- 由于快指针和慢指针的速度差是1步,而移动的最短距离也是1步,因此有环必相遇。
- 也可以用反证法:
假设链表存在环,而快慢二者不会相遇,则只可能出现一种情况:慢指针超越了快指针1步。慢指针往前推1步,快指针往前推2步,二者相遇,说明假设不成立。
- 时间复杂度: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)
return false;
ListNode *fast = head->next;
ListNode *slow = head;
while(fast!=slow){
if(!fast||!fast->next)//fast走到链表尾
return false;
fast = fast->next->next;
slow = slow->next;
}
return true;
}
};
- 不修改链表
- set存结点地址(唯一标识):使用的方法find
- 时间复杂度:o(n),空间复杂度o(n)
/**
* 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) {
set<ListNode*> nodes;
while(head){
set<ListNode*>::iterator iter = nodes.find(head);
if(iter!=nodes.end())
return true;
nodes.insert(head);
head = head->next;
}
return false;
}
};
- 使用哈希表:unordered_set/hash_set,性能比set稍高
- 时间复杂度:o(n) 空间复杂度:o(n)
- hash_set和unordered_set?
- unordered_set同hast_set都是属于基于哈希表(hash table)构建的数据结构,但unordered_set引入了c++11标准库中,而hash_set没有,所以使用hash_set在leetcode上会编译不通过
- hash_set定义麻烦,unordered_set定义简单,和set一样
- set和unordered_set/hash_set?
- set的内部结构是基于红黑树来实现的
- 在一个unordered_set内部,元素不会按任何顺序排序,而是通过元素值的hash值将元素分组放置到各个桶中,这样就能通过元素值快速访问各个对应的元素(均摊耗时为O(1));set中元素是自动排序的
- 参考:
/**
* 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*> nodes;
while(head){
unordered_set<ListNode*>::iterator iter = nodes.find(head);
if(iter!=nodes.end())
return true;
nodes.insert(head);
head = head->next;
}
return false;
}
};