提交版本1,我自己写的
/**
* 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) {
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
slow = head;
while (fast!=slow)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
}
return nullptr;
}
};
答案:
ListNode* detectCycle(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) break;
}
// 上面的代码类似 hasCycle 函数
if (fast == nullptr || fast->next == nullptr) {
// fast 遇到空指针说明没有环
return nullptr;
}
// 重新指向头结点
slow = head;
// 快慢指针同步前进,相交点就是环起点
while (slow != fast) {
fast = fast->next;
slow = slow->next;
}
return slow;
}
很明显看到第二种代码执行更快一点,因为在快慢指针第一次相遇(证明存在环)的时候,就直接跳出循环了:
if (fast == slow) break;
而第一种代码写成这样,还是因为是站在逻辑的角度思考(是新手):当相遇时,将一个指针指向开头,然后二者同时往前走,当相遇时就返回slow,忘了循环是可以先跳出来的(因为相遇以后的过程不再需要了)。 而第二种明显是站在代码的角度,当相遇时,while循环就没有必要继续了,所以直接跳出循环,再加一个if判断,如果满足情况,直接返回nullptr不用管后面,不满足再继续走,全程没有走多余的任何一步。相比之下第一种就多了很多没必要的判断,显得赘余。