142.环形链表
描述:
思路:
- 在知道链表的基础知识以及看了LeetCode给的代码头, 入参和出参很清楚, 很好理解题目的意思和需求.
- 可以直接想到的方法, 就是直接遍历, 也就是官方题解的第一种方法, 即把每个节点存到哈希表中, 判断是否有重复元素, 然后返回就行了, 时间复杂度还行(O(n)), 空间复杂度为(O(n)), 自然是可以优化的.
- 另一种方法就是双指针法, 具体分析步骤参考代码随想录写的很详细了, 这里只根据分析后的结论总结一下步骤:
- 用两个指针去遍历链表, 快指针
fast一次遍历两个元素, 慢指针slow一次遍历一个元素 - 在遍历过程中, 若快慢指针指向元素相同时, 即可判定为链表有环, 反之即无环.
- 当快慢指针相遇, 声明一个头指针, 和一个指向相遇元素位置的指针(可直接复用slow), 开始遍历, 每次遍历一个元素.
- 当两个指针相遇, 相遇时所指向的元素即为环的入口元素, 返回即可.
- 用两个指针去遍历链表, 快指针
代码:
-
哈希表:
/* * @lc app=leetcode.cn id=142 lang=cpp * * [142] 环形链表 II */ // @lc code=start /** * 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) { std::unordered_set<ListNode *> set; while (head) { if (set.count(head)) return head; set.insert(head); head = head->next; } return nullptr; } }; -
双指针:
/* * @lc app=leetcode.cn id=142 lang=cpp * * [142] 环形链表 II */ // @lc code=start /** * 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 != nullptr && fast->next != nullptr) { fast = fast->next->next; slow = slow->next; if (fast == slow) { ListNode *p = head; while (p != slow) { p = p->next; slow = slow->next; } return p; } } return nullptr; } };
参考:
[1] 官方题解
[2] 代码随想录