/**
* Source : https://oj.leetcode.com/problems/linked-list-cycle-ii/
*
* Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
*
* Follow up:
* Can you solve it without using extra space?
*/
public class LinkedListCycle2 {
/**
* 如果链表是循环的,则找到循环的开始节点
* 否则,返回null
*
* 依然使用双指针法,如果是循环链表的话,
* slow和fast第一次相遇之后,将slow = head,
* 然后将slow和fast每次移动一个节点,第二次相遇的时候就是循环的起始节点
*
* 原理:
* 假设head到start的距离a,slow和fast第一次相遇的位置距离start为b,循环链表周长为c,第一次相遇的时候fast走过的长度一定是slow的两倍,在过程中遍历了循环链表n次
* (a + b) * 2 = a + n * c + b
* 那么a = n*c - b => a + b = n*c
* 也就是说,现在让两个指针slow指向head,fast指向第一次相遇的位置,然后每次两个指针移动一个节点,直到下一次相遇,正好走过n个周长,即下一次相遇在start位置
*
* @param head
* @return
*/
public LinkedNode findCycleStart (LinkedNode head) {
if (head == null) {
return null;
}
LinkedNode slow = head;
LinkedNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
if (fast == slow) {
// 链表存在循环
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
return null;
}
private class LinkedNode {
int value;
LinkedNode next;
}
/**
* 创建普通的链表
* @param arr
* @return
*/
public LinkedNode createList (int[] arr) {
if (arr.length == 0) {
return null;
}
LinkedNode head = new LinkedNode();
head.value = arr[0];
LinkedNode pointer = head;
for (int i = 1; i < arr.length; i++) {
LinkedNode node = new LinkedNode();
node.value = arr[i];
pointer.next = node;
pointer = pointer.next;
}
return head;
}
/**
* 将链表变为循环链表,循环起始为第index个node
* @param head
* @param index
*/
public void makeCycle (LinkedNode head, int index) {
if (head == null) {
return;
}
LinkedNode tail = head;
int count = 1;
while (tail.next != null) {
tail = tail.next;
count++;
}
LinkedNode p = head;
if (index > count) {
index = index % count;
} else if (index < 0) {
index = Math.abs(index);
}
while (p != null) {
index--;
if (index < 1) {
tail.next = p;
break;
}
p = p.next;
}
}
public static void main(String[] args) {
LinkedListCycle2 linkedListCycle = new LinkedListCycle2();
LinkedNode list = linkedListCycle.createList(new int[]{1,2,3,4,5});
System.out.println(linkedListCycle.findCycleStart(list) + " == null");
linkedListCycle.makeCycle(list, 2);
System.out.println(linkedListCycle.findCycleStart(list).value + " == 2");
}
}