[链表]找出两个链表第一个公共节点

标签:链表,hash
题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

解题思路

  • 一种方法是用 hashmap来存储和查找节点;
    另一种方法是双指针法。
    注意复习HashSet和HashMap的插入查询等用法

  • 另一种就是著名的快慢指针法。在牛客网上找了个好理解的解释:

    • 第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。

    • 第二步,找环的入口。接上步,当p1 == p2时,设p2所经过节点数为2x, p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x;(假设n很大,只多走了一圈) n=x; 可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口(可以画图,一目了然)。

    • 所以,我们设置两个指针,一个是快指针fast,一个是慢指针slow,fast一次走两步,slow一次走一步,如果单链表有环那么当两个指针相遇时一定在环内。此时将一个指针指到链表头部,另一个不变,二者同时每次向前移一格,当两个指针再次相遇时即为环的入口节点。如果fast走到null则无环。

参考代码
  • HashSet
import java.util.HashSet;
/*
 * 方法一:hashset存每个节点,第一个重复的就是环入口,空间复杂度O(n)
 */

public static ListNode EntryNodeOfLoop(ListNode pHead) {
    //可以不写
	if(pHead == null)
		return null;
	HashSet<ListNode> set = new HashSet<>();
	while(pHead != null && pHead.next != null){
		if(set.contains(pHead))
			return pHead;
		else {
			set.add(pHead);
		}
		pHead = pHead.next;
	}
	return null;
}
  • 方法二,快慢指针
    正常写法:
public static ListNode EntryNodeOfLoop1_1(ListNode pHead) {
	if(pHead == null || pHead.next == null)
		return null;
	ListNode fast = pHead;
	ListNode slow = pHead;
	while(fast != null && fast.next != null) {
		// 根据结论,如果相遇,fast回到头结点,两个一起走
		fast = fast.next.next;
		slow = slow.next;		
		if(fast == slow) {
			break;
		}			
	}
	//判空
	if(fast == null || fast.next == null)
		return null;
	else {
		fast = pHead;
		while(fast != slow) {
			fast = fast.next;
			slow = slow.next;
		}
	}

	return slow;
}

改进写法:

public static ListNode EntryNodeOfLoop1(ListNode pHead) {
	if(pHead == null || pHead.next == null)
		return null;
	ListNode fast = pHead;
	ListNode slow = pHead;
	while(fast != null && fast.next != null) {
		//这两句在前,不然结果错误,想想为什么?
		//因为初始时是相等的啊
		fast = fast.next.next;
		slow = slow.next;		
		// 根据结论,如果相遇,fast回到头结点,两个一起走
		if(fast == slow) {
			fast = pHead;
			while(fast != slow) {
				fast = fast.next;
				slow = slow.next;
			}
			return fast;
		}
	}
	//能运行到这里,说明没有环
	return null;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值