數據結構與算法(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);

	}

}

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