兩條單鏈表的處理問題

一、兩個有序鏈表的公共部分

在這裏插入圖片描述
思路:雙指針

public static class Node{
		int value;
		Node next;
		public Node(int value) {
			this.value = value;
		}
	}
	public static void f(Node head1,Node head2) {
		Node first = head1;
		Node second = head2;
		while(first!=null && second!=null) {
			if(first.value < second.value) first= first.next;
			else if(first.value > second.value) second= second.next;
			else {
				System.out.println(first.value+" ");
				first = first.next;
				second = second.next;
			}
		}
	}
	public static void main(String[] args) {
		Node node1 = new Node(2);
		node1.next = new Node(3);
		node1.next.next = new Node(5);
		node1.next.next.next = new Node(6);
		Node node2 = new Node(1);
		node2.next = new Node(2);
		node2.next.next = new Node(5);
		node2.next.next.next = new Node(7);
		node2.next.next.next.next = new Node(8);
		f(node1,node2);
	}

二、判斷一個鏈表是否是迴文結構

在這裏插入圖片描述
思路:將鏈表逆置與原鏈表比較
逆置方法一:利用棧結構:可以將鏈表所有元素都壓入棧再彈出,也可以將後半部分壓入棧再彈出
逆置方法二:可以直接改變鏈表節點的指向,不用額外的空間開銷,在原鏈表上直接將鏈表後半部分逆置

方法一實現:

public static boolean isPalind(Node head) {
		Stack<Integer>stack = new Stack<>();
		Node curr = head;
		while(curr != null) {
			stack.push(curr.value);
			curr = curr.next;
		}
		curr = head;
		while(!stack.isEmpty()) {
			if(curr.value != stack.peek()) {
				return false;
			}
			curr = curr.next;
			stack.pop();
		}
		return true;
	}

方法二實現:

	//存儲鏈表後半部分
	public static boolean isPalind(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Stack<Integer>stack= new Stack<>();
		Node fast = head.next;
		Node slow = head;
		while(fast!=null && fast.next.next!=null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		while(slow!=null) {
			stack.push(slow.value);
			slow = slow.next;
		}
		slow = head;
		while(!stack.isEmpty()) {
			if(slow.value != stack.peek()) return false;
			slow = slow.next;
			stack.pop();
		}
		return true;
	}

方法三實現:

public static boolean isPalindrome3(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Node n1 = head;
		Node n2 = head;
		while (n2.next != null && n2.next.next != null) { // find mid node
			n1 = n1.next; // n1 -> mid
			n2 = n2.next.next; // n2 -> end
		}
		n2 = n1.next; // n2 -> right part first node
		n1.next = null; // mid.next -> null
		Node n3 = null;
		while (n2 != null) { // right part convert
			n3 = n2.next; // n3 -> save next node
			n2.next = n1; // next of right node convert
			n1 = n2; // n1 move
			n2 = n3; // n2 move
		}
		n3 = n1; // n3 -> save last node
		n2 = head;// n2 -> left first node
		boolean res = true;
		while (n1 != null && n2 != null) { // check palindrome
			if (n1.value != n2.value) {
				res = false;
				break;
			}
			n1 = n1.next; // left to mid
			n2 = n2.next; // right to mid
		}
		n1 = n3.next;
		n3.next = null;
		while (n1 != null) { // recover list
			n2 = n1.next;
			n1.next = n3;
			n3 = n1;
			n1 = n2;
		}
		return res;
	}

三、鏈表的相交問題

在這裏插入圖片描述
情況一:兩個無環鏈表
在這裏插入圖片描述
不可能是X形狀,因爲單鏈表只能有一個指針
方法一:哈希,將第一條鏈表用哈希表存儲,遍歷第二條鏈表,找到包含的key就返 回,否則不存在

public static Node  getFirstLoopNode(Node head) {
		HashSet<Node>set = new HashSet<>();
		while(head != null) {
			if(set.contains(head)) return head;
			set.add(head);
			head = head.next;
		}
		return null;
	}

方法二:快慢指針,快指針一次兩步,慢指針一次一步,如果有環第一次相遇將快指針返回頭結點,然後和慢指針以相同的速度移動,再次相遇的時候就是環入口(這種方法網上有很多詳解,大家可以查閱)

方法三:
遍歷第一個鏈表長度爲n1,遍歷第二個鏈表長度爲n2,長的鏈表先走|n2-n1|步,然後兩個鏈表一起走,肯定會同時到達相交節點

情況二:一個無環一個有環
這種情況下,不可能存在相交節點,這樣肯定有一個節點存在兩個指針

情況三:兩個有環鏈表
在這裏插入圖片描述
如何判斷是左邊還是右邊情況???
利用兩個指針,當他們相遇的時候,其中一個指針A繼續往前,另外一個指針B不動,如果A會和B相遇那麼就是第二種情況否則是第一種。

小結:

1.利用快慢指針法求出第一條鏈表的第一個入環節點loop1,第二條鏈表的第一個入環節點loop2
2.如果loop1null && loopnull 就是兩個無環鏈表的相交問題,遍歷鏈表找出最後一個節點和長度,如果最後一個鏈表不相等一定不相交,否則可以按上述方法
3.如果一個loop爲null,一定不想交
4.判斷loop1與loop2是否相等,如果相交就是答案,否則用上述判斷是否是66的形式加之判斷。

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