数据结构与算法(JAVA版)6_5:给定两个可能有环也可能无环的单链表,头结点head1和head2.请实现一个函数,如果两个链表相交,请返回相交的第一个节点,如果不相交,返回null

给定两个可能有环也可能无环的单链表,头结点head1和head2.请实现一个函数,如果两个链表相交,请返回相交的第一个节点,如果不相交,返回null
要求:
如果两个链表长度之和为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)

先解决这样一个问题:

给定一个存在环的单链表,请找出环的入口结点,如果一个单链表的首尾结点是同一个结点,则默认首结点为环的入口结点。

package com.inspire.chapter6;

public class Code05_FindFirstIntersectNode1 {

	public static class Node {
		public int value;
		public Node next;

		public Node(int v) {
			value = v;
		}
	}

	//判断单链表是否存在环,有环返回环的入口结点,无环返回null
	public static Node getLoopNode(Node head) {
		if (head == null || head.next == null || head.next.next == null) {
			return null;
		}
		Node slow = head.next;
		Node fast = head.next.next;
		while (slow != fast) {
			if (fast.next == null || fast.next.next == null) {
				return null;
			}
			slow = slow.next;
			fast = fast.next.next;
		}
		fast = head;
		while (slow != fast) {
			slow = slow.next;
			fast = fast.next;
		}
		return slow;
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.next = new Node(2);
		head.next.next = new Node(3);
		head.next.next.next = new Node(4);
		head.next.next.next.next = new Node(5);
		head.next.next.next.next.next = new Node(6);
		head.next.next.next.next.next.next = new Node(7);
		head.next.next.next.next.next.next.next = head.next.next.next;
		System.out.println(getLoopNode(head).value);

	}

}

接下来解决这道题

假设链表head1和链表head2各自的入环结点分别为loop1和loop2
1.loop1=null,loop2=null;
首先判断这两个链表是否存在环,当两个链表都不存在环时
情况1:两个链表的不相交,返回null,判断方法:两个链表的尾结点不相等;
情况2:两个链表相交,返回相交结点,判断方法,分别存在两个结点相等。
2.loop1=null,loop2!=null;loop1!=null,loop2=null;这种两种情况下两个链表是不会相交的
3.loop1!=null,loop2!=null;
情况一:两个链表没有共同结点(不相交)
情况二:两个链表的相交结点不在环上(也即入环结点相等)
情况三:两个链表的相交结点在环上(也即入环结点不相等)

package com.inspire.chapter6;

import com.inspire.chapter6.Test2.Node;

public class Code05_FindFirstIntersectNode {

	public static class Node {
		public int value;
		public Node next;

		public Node(int v) {
			value = v;
		}
	}

	// 判断单链表是否存在环,有环返回环的入口结点,无环返回null
	public static Node getLoopNode(Node head) {
		if (head == null || head.next == null || head.next.next == null) {
			return null;
		}
		Node slow = head.next;
		Node fast = head.next.next;
		while (slow != fast) {
			if (fast.next == null || fast.next.next == null) {
				return null;
			}
			slow = slow.next;
			fast = fast.next.next;
		}
		fast = head;
		while (slow != fast) {
			slow = slow.next;
			fast = fast.next;
		}
		return slow;
	}

	// 根据两个无环链表查找相交结点,有则返回相交结点,没有则返回null
	public static Node noLoop(Node head1, Node head2) {
		if (head1 == null || head2 == null) {
			return null;
		}
		// 判断两个单链表的尾结点是否相等,不相等则返回null,相等则继续
		Node cur1 = head1;
		Node cur2 = head2;
		int n = 0;// 保存两个单链表长度的差值
		while (cur1 != null) {
			n++;
			cur1 = cur1.next;
		}
		while (cur2 != null) {
			n--;
			cur2 = cur2.next;
		}
		if (cur1 != cur2) {// 说明不相交
			return null;
		}
		cur1 = n > 0 ? head1 : head2;// cur1指向较长的单链表
		cur2 = cur1 == head1 ? head2 : head1;// cur2指向较短的单链表
		n = Math.abs(n);
		while (n != 0) {
			n--;
			cur1 = cur1.next;
		} // 退出循环后,较长的单链表中cur1指向结点开始的单链表已经和较短的单链表长度相等了
		while (cur1 != cur2) {
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		return cur1;
	}

	// 两个有环链表,返回第一个相交节点,如果不想交返回null
	/*
	 * loop1:链表head1的入环结点 loop2:链表head2的入环结点
	 */
	public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {

		if (loop1 == loop2) {// 这是情况二
			Node cur1 = head1;
			Node cur2 = head2;

			int n = 0;
			while (cur1 != loop1) {
				n++;
				cur1 = cur1.next;
			}
			while (cur2 != loop1) {
				n--;
				cur2 = cur2.next;
			}
			cur1 = n > 0 ? head1 : head2;
			cur2 = cur1 == head1 ? head2 : head1;
			n = Math.abs(n);
			while (n != 0) {
				n--;
				cur1 = cur1.next;
			}
			while (cur1 != cur2) {
				cur1 = cur1.next;
				cur2 = cur2.next;
			}
			return cur1;
		} else {// 讨论情况一和情况三
			Node cur1 = loop1.next;
			while (cur1 != loop1) {
				if (cur1 == loop2) {
					return loop1;
				}
				cur1 = cur1.next;
			}
			return null;
		}
	}

	public static Node getIntersectNode(Node head1, Node head2) {
		if (head1 == null || head2 == null) {
			return null;
		}
		Node loop1 = getLoopNode(head1);
		Node loop2 = getLoopNode(head2);
		if (loop1 == null && loop2 == null) {
			return noLoop(head1, head2);
		} else if (loop1 != null && loop2 != null) {
			return bothLoop(head1, loop1, head2, loop2);
		}
		return null;

	}

	public static void main(String[] args) {
		// 1->2->3->4->5->6->7->null
		Node head1 = new Node(1);
		head1.next = new Node(2);
		head1.next.next = new Node(3);
		head1.next.next.next = new Node(4);
		head1.next.next.next.next = new Node(5);
		head1.next.next.next.next.next = new Node(6);
		head1.next.next.next.next.next.next = new Node(7);

		// 0->9->8->6->7->null
		Node head2 = new Node(0);
		head2.next = new Node(9);
		head2.next.next = new Node(8);
		head2.next.next.next = head1.next.next.next.next.next; // 8->6
		System.out.println(getIntersectNode(head1, head2).value);

		// 1->2->3->4->5->6->7->4...
		head1 = new Node(1);
		head1.next = new Node(2);
		head1.next.next = new Node(3);
		head1.next.next.next = new Node(4);
		head1.next.next.next.next = new Node(5);
		head1.next.next.next.next.next = new Node(6);
		head1.next.next.next.next.next.next = new Node(7);
		head1.next.next.next.next.next.next = head1.next.next.next; // 7->4

		// 0->9->8->2...
		head2 = new Node(0);
		head2.next = new Node(9);
		head2.next.next = new Node(8);
		head2.next.next.next = head1.next; // 8->2
		System.out.println(getIntersectNode(head1, head2).value);

		// 0->9->8->6->4->5->6..
		head2 = new Node(0);
		head2.next = new Node(9);
		head2.next.next = new Node(8);
		head2.next.next.next = head1.next.next.next.next.next; // 8->6
		System.out.println(getIntersectNode(head1, head2).value);

	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章