算法 (十二)链表相关:判断两个链表是否相交,并返回交点

1、判断两个链表是否相交,并返回交点

1.1 简单描述

其实这是一个综合题,属于链表里面最难的了(好像面试管特别喜欢考这个),因为判断链表相交之前你需要先判断链表是否有环

1.2 思路
  1. 先判断两个链表是否有环(两种方法,辅助hashset或用快慢指针),找到入环点
  2. 两个都无环,判断相交(两种方法,辅助hashset或计算链表长度差N然后长链表先走N步,然后一起走,相遇即为交点,也可以将两个链表放到两个栈里,一起弹栈)
  3. 两个都有环(一个有环一个没环肯定是不相交的,因为如果相交就是两个有环链表了,相悖),看两个环的入环点是否一样,分三种情况,具体请看下面的手绘图

在这里插入图片描述

具体代码实现如下:

package cn.nupt;

import java.util.HashSet;

/**
 * @Description: 如果两链表相交,输出第一个相交的节点(前面还会考虑这两个链表是否有环)
 *
 * @author PizAn
 * @Email pizan@foxmail.com
 * @date 2019年2月19日 下午11:11:20
 * 
 */
public class FindFirstIntersectNode {
   

	// 构建链表结构,这里是静态内部类
	public static class Node {
   
		int value;
		Node next;

		// 再来个构造方法
		public Node(int value) {
   
			this.value = value;
		}
	}

	// 判断两个链表是否相交,并返回相交点
	public static Node findFirstIntersectNode(Node head1, Node head2) {
   
		// 先来个鲁棒性判断
		if (head1 == null || head2 == null) {
   
			return null;
		}

		// 1、看两个链表是否有环,并返回入环点loopPoint
		Node loopPoint1 = ishuanWithTwoPoint(head1);
		Node loopPoint2 = ishuanWithTwoPoint(head2);

		// 2、如果都没环
		if (loopPoint1 == null && loopPoint2 == null) {
    // 都不是环
			return noLoop(head1, head2);
		} else if (loopPoint1 != null && loopPoint2 != null) {
    // 都是环
			return bothLoop(head1, head2, loopPoint1, loopPoint2);

		}
		// 一个有环一个无环,肯定不相交(相交了就变成两个有环了,相悖),直接返回null
		return null;

	}

	// 1、判断链表是否有环(用外部辅助结构:hashSet或者hashMap,将节点当作键存入集合(set/map不能存重复的键),然后调用集合的contains(Object
	// key)的方法
	// 如果检测到重复存储就说明有环,如果没有,就是无环)
	public static Node ishuanWithHashSet(Node head) {
    // 这里返回入环点
		HashSet<Node> set = new HashSet<Node>();
		// HashMap<Node, Node> map = new HashMap<Node, Node>();
		// 感觉这种用map或者set的方法好像不行,因为单链表你把节点存到集合中的时候,也有可能
		// (我擦,突然想起来吗,这个存的是Node,就算Node.value一样,这个Node.next也不一样的,所以,可行!!!)

		Node cur = head;
		while (cur != null) {
   
			if (set.contains(cur)) {
    // 检测是否重复存储
				return cur; // 如果重复存储了,这个点就是入环点

			}
			set.add(cur);
			cur = cur.next;

		}

		return null;

	}

	// 第二种方法,用快慢指针,快走2,慢走1,若相遇则有环,再来一个指针从head开始,和这个相遇点指针一起走,再相遇就是入环点(可以自己画一画,挺玄学的)
	public static Node ishuanWithTwoPoint(Node head) {
   
		if (head == null) {
   
			return head;
		}
		Node slow = head;
		Node fast = head;

		while (fast.next != null && fast.next.next != null) {
   
			slow = slow.next;
			fast = fast.next.next;

			if (slow == fast) {
    // 相遇,说明有环
				Node cur = head;
				while (cur != slow) {
    // 来一个指针从head开始,和这个相遇点指针一起走,再相遇就是入环点
					cur = cur.next;
					slow = slow.next;

				}
				return slow;
			}

		}

		return null; // 什么都没有,就是无环

	}

	// 说完了有环没环,下面开始说相交
	// 1、两个都无环,第一种是将表1放到set中,再遍历表2,若重复contains,则相交,且为交点(挺简单的,在此不表)
	// 2、两个都无环,第二种是遍历两个链表,如果到最后都没相交,就没有,如果相交,分别计算两个链表的长度,相差为n,长的先跑n步,然后一起跑,第一次相遇的就是交点

	// 1、两个都有环,有三种情况,具体请看手绘图

	private static Node noLoop(Node head1, Node head2) {
   
		// 1、先知道两个链表的长度
		int long1 = 0;
		int long2 = 0;
		Node cur1 = head1;
		Node cur2 = head2;
		while (cur1.next != null) {
   
			long1++;
			cur1 = cur1.next;

		}
		while (cur2.next != null) <
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值