141 环形链表I
题目描述
思路 哈希/快慢指针
面经里面的常驻军,好早之前就打算做,一直拖到今天才做
哈希就没啥好说的了,用insert的第二个返回的参数second判断是否插入失败,或者用哈希集合的count判断是否大于0都行
而快慢指针的话,快指针每次移动两位,慢指针每次移动一位,这样在环中每次差一步,一定能追上慢指针
快慢指针需要注意:如果初始都设为head,如果while循环的终止条件为fast == slow,那么第一次进去就结束了,所以至少应该进行一次移动后再判定。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//存储结点,寻找重复结点,用hashmap、set都行
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> seen;
while (head != nullptr) {
if (seen.count(head)) {
return true;
}
seen.insert(head);
head = head->next;
}
return false;
}
};
//快慢指针
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == nullptr || head -> next == nullptr) {
return false;
}
ListNode* slow = head;
ListNode* fast = head;
while(fast && fast ->next) {
slow = slow -> next;
fast = fast -> next -> next;
if(fast == slow) {
return true;
}
}
return false;
}
};
142 环形链表II
题目描述
思路 双指针
需要找到环的入口位置。
这就需要我们对快慢指针走了多少步有清楚的认识。
设快指针走f步,慢指针走s步。我们同样使快指针每次走两步,慢指针走一步,显而易见f = 2s。
当相遇的时候,快指针会多走慢指针n倍环的距离,设环长度为b,则f = s + nb
联立可得 s = nb f = 2nb
那么我们就可以得知,相遇的时候s处于nb位置,且我们设环之前的长度a,能够得知环的入口地址为a + nb(n∈R)处(此n非彼n)
所以我们只要让慢指针再走a步即可。但现在问题是a是未知的,所以再次利用双指针,设一个新的指针指向head结点,两边都移动a的时候就会在环开头相遇。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//用快慢指针必须知道相遇的地方在哪
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == nullptr || head -> next == nullptr) {
return nullptr;
}
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast -> next) {
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow) {
fast = head;
while(fast != slow) {
slow = slow -> next;
fast = fast -> next;
}
return fast;
}
}
return nullptr;
}
};
这里要注意的是,可能存在没有环的情况,如果把两个while循环拆开,进行下一个循环要判断一下fast或者fast -> next是否为空
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
//用快慢指针必须知道相遇的地方在哪
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == nullptr || head -> next == nullptr) {
return nullptr;
}
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast -> next) {
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow) {
break;
}
}
if(fast == nullptr || fast -> next == nullptr ) return nullptr;
fast = head;
while(fast != slow) {
slow = slow -> next;
fast = fast -> next;
}
return fast;
}
};
因为fast会一下移动两个位置,所以可能本身就是空,也可能下一个位置为空。最好还是按照第一种写,以防自己忘记。
时间复杂度O(n)
空间复杂度O(1)