Featured image of post 142. Linked List Cycle II

142. Linked List Cycle II

142.Linked List Cycle II

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * @lc app=leetcode id=142 lang=java
 *
 * [142] Linked List Cycle II
 *
 * https://leetcode.com/problems/linked-list-cycle-ii/description/
 *
 * algorithms
 * Medium (51.25%)
 * Likes:    13392
 * Dislikes: 937
 * Total Accepted:    1.3M
 * Total Submissions: 2.5M
 * Testcase Example:  '[3,2,0,-4]\n1'
 *
 * Given the head of a linked list, return the node where the cycle begins. If
 * there is no cycle, return null.
 * 
 * There is a cycle in a linked list if there is some node in the list that can
 * be reached again by continuously following the next pointer. Internally, pos
 * is used to denote the index of the node that tail's next pointer is
 * connected to (0-indexed). It is -1 if there is no cycle. Note that pos is
 * not passed as a parameter.
 * 
 * Do not modify the linked list.
 * 
 * 
 * Example 1:
 * 
 * 
 * Input: head = [3,2,0,-4], pos = 1
 * Output: tail connects to node index 1
 * Explanation: There is a cycle in the linked list, where tail connects to the
 * second node.
 * 
 * 
 * Example 2:
 * 
 * 
 * Input: head = [1,2], pos = 0
 * Output: tail connects to node index 0
 * Explanation: There is a cycle in the linked list, where tail connects to the
 * first node.
 * 
 * 
 * Example 3:
 * 
 * 
 * Input: head = [1], pos = -1
 * Output: no cycle
 * Explanation: There is no cycle in the linked list.
 * 
 * 
 * 
 * Constraints:
 * 
 * 
 * The number of the nodes in the list is in the range [0, 10^4].
 * -10^5 <= Node.val <= 10^5
 * pos is -1 or a valid index in the linked-list.
 * 
 * 
 * 
 * Follow up: Can you solve it using O(1) (i.e. constant) memory?
 * 
 */

// @lc code=start
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 * 
 * 思路:使用弗洛伊德判圈算法,即快慢指針,
 *      畫圖輔助,
 *     1若快慢指針能相遇,則存在環,
 *     2然後設置2個新指針,一個從頭節點開始,另一個指針從相遇節點開始,當兩指針相遇處即為環的入口節點 
 * 
 * 
 * 使用快慢指针检测链表中循环的原理是一种常见且高效的算法,也被称为Floyd's Tortoise and Hare Algorithm(弗洛伊德的乌龟和兔子算法)。这种算法通过使用两个指针,一个快指针和一个慢指针,来检测链表中是否存在循环,并找到循环的起始节点。

快慢指针的原理是,快指针每次移动两步,慢指针每次移动一步。如果链表中存在循环,快指针最终会追上慢指针。这是因为快指针的速度是慢指针的两倍,所以在循环中,快指针会绕圈追赶慢指针,最终相遇。

当快慢指针相遇时,我们可以得出以下结论:

链表中存在循环。
通过数学推导,可以确定链表中循环的起始节点。
具体来说,假设链表头到循环起始节点的距离为A,循环起始节点到快慢指针相遇点的距离为B。根据快慢指针的移动规律,可以得出以下等式:快指针走过的距离 = 2 * 慢指针走过的距离。根据这个等式,可以推导出A = C,即链表头到循环起始节点的距离等于相遇点到循环起始节点的距离。

因此,当快慢指针相遇后,我们可以设置一个新的指针从链表头开始,与相遇点的指针同时移动,它们相遇的节点就是循环的起始节点。

通过这种方法,我们可以高效地检测链表中的循环,并找到循环的起始节点,而且算法的时间复杂度为O(N),空间复杂度为O(1)
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //需要确保快指针與快指針的下一个节点不为空,以避免空指针异常
        while (fast != null && fast.next !=null) {
            fast = fast.next.next;
            slow = slow.next;
            //相遇則存在環
            if(slow == fast){
                ListNode index1 = fast;
                //在检测到快慢指针相遇时,需要重新设置一个新的指针从头节点开始,以找到循环的入口点
                ListNode index2 = head;
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                //index1與index2在環的入口處相遇
                return index1;
            }
        }
        return null;    
    }
}
// @lc code=end
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy