程序员面试经典--链表环路检测与入口结点返回

2.6问题:

给定一个有环链表,实现一个算法返回环路的开头结点。

思考:

第一:监测链表是否存在环路。有一种简单的方法叫做fastrunner/slowrunner法。fastruner一次移动两步,slowrunner一次移动一步。如果存在环路,最终必然会碰到一起。

第二:什么时候碰到一起?

    1、slowrunner处于环路中的0步位置;

    2、fastrunner处于环路中的k步位置;

    3、slowrunner落后于fastrunner,相距k步;

    4、fastrunner落后于slowrunner,相距LOOP_SIZE-k步;

那么,若fastrunner 落后于slowrunner,相距LOOP_SIZE-k步,那么两者将会在LOOP_SIZE-k步之后相遇。此时,两者与环路起始处相距k步,我们将这个位置称为collisionSopt。

第三:如何找到环路起始处?现在我们知道,collisionSpot与环路起始处相距k个结点。即:collisionSpot和linkedListHead与环路起始处均相距k个结点。现在,若用一个指针指向collisionspot,用另一个指针指向linkedlisthead,两者与loopstart相距k个结点。以同样的速度移动,这两个指针会再次碰在一起------这次是在k步之后,此时两个指针都指向loopstart,然后只需返回该结点即可。


算法思路:

1、创建两个指针:fastpointer和slowpointer。

2、slowpointer每走一步,fastpointer就走两步。

3、两者碰在一起时,将slowpointer指向linkedlisthead,fastpointer保持不变。

4、以相同的速度移动slowpointer和fastpointer,一次一步,然后返回新的碰撞处。

import java.util.*;

//节点类
class Node {
	protected Node next; //指针域
	protected int data;//数据域
	 
	public Node( int data) {
		this.data = data;
	}
	 
	//显示此节点
	public void display() {
		System. out.print( data + " ");
	}
}

//单链表
class LinkList {
	public Node first; // 定义一个头结点
	private int pos = 0;// 节点的位置

	public LinkList() {
		this.first = null;//this代表当前类
	}

	// 插入一个头节点
	public void addFirstNode( int data) {
		Node node = new Node(data);
		node. next = first;
		first = node;
	}

	// 显示出所有的节点信息
	public void displayAllNodes() {
		Node current = first;
		while (current != null) {
			current.display();
			current = current. next;
		}
		System. out.println();
	}

}

class findBeginning{
	public static void main(String args[]){
		LinkList linkList = new LinkList();
		linkList.addFirstNode(11);//56
		Node tail=linkList.first;
		
		linkList.addFirstNode(10);//456
		linkList.addFirstNode(9);//3456
		linkList.addFirstNode(8);//23456
		linkList.addFirstNode(7);//123456
		linkList.addFirstNode(6);//6
		linkList.addFirstNode(5);//56
		linkList.addFirstNode(4);//456
		Node aa=linkList.first;
		
		linkList.addFirstNode(3);//3456
		linkList.addFirstNode(2);//23456
		linkList.addFirstNode(1);//123456
		System.out.println("原链表为:");
		linkList.displayAllNodes();
		//构造环路。
		tail.next = aa;//将第11个结点指向第4个结点形成环路。
		System.out.println("环路入口结点数据为:"+findBeginning(linkList.first).data);
	}
	
	public static Node findBeginning(Node head){
		Node slow=head;
		Node fast=head;
		
		while(fast!=null&&fast.next!=null){
			slow=slow.next;
			fast=fast.next.next;
			if(slow == fast){
				break;
			}
		}
		if(fast==null||fast.next==null){
			return null;
		}
		slow=head;
		while(slow!=fast){
			slow=slow.next;
			fast=fast.next;
		}
		return fast;
	}
}

你可能感兴趣的:(程序员面试经典,Java)