剑指offer第二版-23链表中环的入口节点

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/TTTZZZTTTZZZ/article/details/87910659
import java.util.*;

/**
 * 一个链表中包含环,请找出该链表的环的入口结点。
 * <p>
 * 解决此题需要两步操作 首先确定这个链表是否包含环,若包含环,求出它的入口节点
 *
 * @author VicterTian
 * @version V1.0
 * @Date 2019/2/24
 */
public class P139_EntryNodeOfLoop {
	static class ListNode<T> {
		T val;
		ListNode<T> next;

		ListNode(T val) {
			this.next = null;
			this.val = val;
		}

		@Override
		@SuppressWarnings("all")
		public String toString() {
			StringBuilder ret = new StringBuilder();
			ret.append("[");
			for (ListNode cur = this; ; cur = cur.next) {
				if (cur == null) {
					ret.deleteCharAt(ret.lastIndexOf(" "));
					ret.deleteCharAt(ret.lastIndexOf(","));
					break;
				}
				ret.append(cur.val);
				ret.append(", ");
			}
			ret.append("]");
			return ret.toString();
		}
	}

	/**
	 * 首先判断链表是否有环,通过设置两个快慢指针,让快指针每次走两步,慢指针一次走一步、
	 * 如果快指针追上了慢指针,那么说明此链表存在环。如果走的快的节点的next为null,说明此链表没有环
	 * <p>
	 * 当相遇时,慢指针在环中走了k步,设环外长度为x,环的长度为n,则快指针一共走了x+m*n步。
	 * m是快指针在环中走的圈数,慢指针一共走了x+k步
	 * 因为快指针是慢指针的二倍,所以可以得到 2(x+k)=x+m*n+k; 化简可得x=m*n-k,慢指针在圈中还剩的步数为n-k步
	 *
	 * @param pHead
	 * @return
	 */
	private static ListNode entryNodeOfLoop(ListNode pHead) {
		if (pHead == null || pHead.next == null) {
			return null;
		}
		ListNode fast = pHead;
		ListNode slow = pHead;
		while (fast != null && fast.next != null) {
			slow = slow.next;
			fast = fast.next.next;
			// 判断是否相遇,相遇后让快指针从头开始走,每次都是走一步,第二次相遇就是环的入口
			if (fast.val == slow.val) {
				fast = pHead;
				while (fast.val != slow.val) {
					fast = fast.next;
					slow = slow.next;
				}
			}

			if (fast.val == slow.val) {
				return slow;
			}
		}
		return null;
	}

	/**
	 * 下面的是断链法,访问过的节点都断开,最后到达的那个节点一定是循环的入口节点。
	 */
	private static ListNode entryNodeOfLoop2(ListNode pHead) {
		if (pHead == null || pHead.next == null) {
			return null;
		}
		ListNode fast = pHead.next;
		ListNode slow = pHead;
		while (fast != null) {
			slow.next = null;
			slow = fast;
			fast = fast.next;
		}
		return slow;
	}

	/**
	 * 将每个元素存储在Set集合里,每次存放的时候利用hash计算是否已经有这个结点
	 * 如果有,说明这个链表存在环。并且这个结点就是环的入口节点
	 *
	 * @param pHead
	 * @return
	 */
	private static ListNode entryNodeOfLoop3(ListNode pHead) {
		Map map = new HashMap();

		while (pHead.next != null) {
			if (!map.containsValue(pHead)) {
				map.put(pHead, pHead);
				pHead = pHead.next;
			} else {
				return pHead;
			}

		}
		return null;
	}

	public static void main(String[] args) {
		ListNode<Integer> node1 = new ListNode<>(1);
		ListNode<Integer> node2 = new ListNode<>(2);
		ListNode<Integer> node3 = new ListNode<>(3);
		ListNode<Integer> node4 = new ListNode<>(4);
		ListNode<Integer> node5 = new ListNode<>(5);

		node1.next = node2;
		node2.next = node3;
		node3.next = node4;
		node4.next = node5;
		node5.next = node3;

		System.out.println("entryNodeOfLoop(node1) = " + entryNodeOfLoop3(node1));

	}
}

猜你喜欢

转载自blog.csdn.net/TTTZZZTTTZZZ/article/details/87910659