剑指offer面试题52:两个链表的公共节点(Java实现)

 题目:输入两个链表,找出它们的第一个公共结点。

方法一:暴力法,时间复杂度为 O(mn)。

思路:在第一链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了他们的公共结点。如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度为O(mn).
 

方法二:利用两个辅助栈,时间复杂度为 O(m + n),空间复杂度为 O(m + n)

思路:如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,最后一个相同的结点就是我们要找的结点。可问题是在单向链表中,我们只能从头结点开始按顺序遍历,最后才能到达尾节点。最后到达的尾节点却要最先被比较,这听起来是不是像后进先出,也是我们就能想到用栈的特点来解决这个问题:分别把两个链表的结点放入两个栈里,这样两个链表的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点。
 

方法三:最优解,时间复杂度为 O(m + n),不用额外的空间。

当两个链表的长度不相同时,如果我们从头开始遍历到达两个栈的尾节点的时间就不一致。其实解决这个问题还有一个更简单的办法:首先遍历两个链表得到他们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到第一个相同的结点就是他们的第一个公共结点。
 

public class test_fifty_two {
	public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2){
		int length1 = getLength(pHead1);
		int length2 = getLength(pHead2);
		
		if(length1 == 0 || length2 == 0)
			return null;
		
		ListNode longListNode = null;
		ListNode shortListNode = null;
		
		if(length1 > length2){
			longListNode = pHead1;
			shortListNode = pHead2;
		}
		else{
			longListNode = pHead2;
			shortListNode = pHead1;
		}
		
		//两条链表相差多少个节点
		int dif = Math.abs(length2 - length1);
		
		//长链表先走dif个节点
		for(int i=0; i < dif; i++){
			longListNode = longListNode.next;
		}
		
		//然后两个链表同时走
		while(longListNode != null && shortListNode != null && longListNode != shortListNode){
			shortListNode = shortListNode.next;
			longListNode = longListNode.next;
		}
		return longListNode;
	}
	
	//获取链表的长度
	private int getLength(ListNode pHead) {
		if(pHead == null)return 0;
		
		int length = 0;
		
		while(pHead.next != null){
			pHead = pHead.next;
			length++;
		}
		return length;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41163113/article/details/86663686
今日推荐