Question:Given a circular linked list, implement an algorithm which returns node at the beginning of the loop.
DEFINITION:Circular linked list: A (corrupt) linked list in which a node’s next pointer points to an earlier node, so as to make a loop in the linked list.
EXAMPLE:Input: A -> B -> C -> D -> E -> C [the same C as earlier] Output: C
思路:
1.判断一个链表是否有环的思路是设置两个指针都从链表头开始,指针1每次前进一步、指针2每次前进两步,如果两个指针最终指向同一个节点则该链表有环,否则无环。因为对于有环链表来说,n和2n实则是同一位置。
2.对于寻找环的开始处,按1所述,指针1和指针2最终会在环内相遇,假设环节点数为n,环开始点距链表头k,相遇点在n-x处(x即为离环开始点距离)。当指针1到达环开始处,指针2在环中已前进k。
3.假设从2的状态开始(即指针1进入环开始),当指针1前进n/2步时,指针2前进2*(n/2)=n步(即指针2刚好绕环一圈回到2中k处)。当指针1到达相遇点n-x处时,指针1共前进(n-x)-n/2=(n/2-x)步,则同时指针2前进2*(n/2-x)=(n-2x)步,此时指针1在n-x处,指针2在n-2x+k处。而按假设此时两者相遇,即n-x = n-2x+k,则可知x=k。即可知两者相遇点距环路开始点的距离与环路开始点与链表头距离相等。
4.则此时将指针1退回至链表头,指针2仍在3的位置,两指针同时每次前进一步,当两者再次相遇时的位置即为环路的开始处,即为题中要求的位置。
package CareerCup;
public class FindStartOfLoop
{
public FindStartOfLoop(){}
public Node find(LinkedList ll)
{
if(ll==null || ll.header==null) return null;
Node loopStart = null;
Node nodeSlow = ll.header;
Node nodeFast = ll.header;
while(nodeSlow!=null && nodeFast!=null)
{
nodeSlow = nodeSlow.next;
if(nodeFast.next==null)
{
loopStart = null;
break;
}
nodeFast = nodeFast.next.next;
if(nodeSlow == nodeFast)
{
nodeSlow = ll.header;
while(nodeSlow!=nodeFast)
{
nodeSlow = nodeSlow.next;
nodeFast = nodeFast.next;
}
loopStart = nodeSlow;
break;
}
}
return loopStart;
}
public static void main(String[] args)
{
int[] data = new int[]{1,2,3,4,5,3};
LinkedList ll = new LinkedList();
ll.creatLoop(data);
System.out.println("The linkedlist:");
for(int i=0;i<data.length;i++)
{
if(i!=data.length-1)
System.out.print(data[i]+"->");
else
System.out.print(data[i]);
}
System.out.println();
FindStartOfLoop fsl = new FindStartOfLoop();
Node loopStart = fsl.find(ll);
System.out.println("The start of loop:"+loopStart.data);
}
}