关键知识
链表的处理
解题思路
一种简单的做法就是顺序遍历每个结点,然后每次都判断该点是否在前面遍历过的结点中,可以采用两层遍历的做法或者是采用set来存储前面的结点,然后每次在set中find这个结点。但是set会将空间复杂度大大增加。
另一种做法就是采用快慢两个指针在链表中遍历,如果快慢指针会相遇,则说明链表中存在环,否则不存在。该做法的时间复杂度为O(n),空间复杂度为O(1),为最佳做法。
简单做法
首先初始化一个set,然后遍历链表,不断地比较该节点是否出现过,出现过则说明存在环,没出现过就将此节点加进set,直到遍历完整个链表。
时间复杂度: 平均为O(n),最差为O(n^2)
空间复杂度: O(n)
最佳解法
采用两个指针分别为fast和slow,fast指针遍历的速度为slow的两倍,如果在fast到达链表结尾时两个指针不相遇,则说明链表不存在环,如果存在环,由于两者速度不一样,必定相遇,且相遇也说明了链表存在环。
时间复杂度: O(n)
空间复杂度: O(1)
题目
简答做法
class Solution {
public:
bool hasCycle(ListNode *head) {
set<ListNode*> sl;
ListNode* p = head;
while (p) {
if (sl.find(p) != sl.end()) return true;
else sl.insert(p);
p = p->next;
}
return false;
}
};
最优解法
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast = head, *slow = head;
if (!head) return false;
if (head->next == nullptr) return false;
if (head->next == head) return true;
fast = head->next ? head->next->next : head->next;
slow = head->next;
while (fast) {
if (fast == slow) return true;
fast = fast->next ? fast->next->next : fast->next;
slow = slow ? slow->next : slow;
}
return false;
}
};