剑指36.两个链表的第一个公共结点
题目描述
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
思路
如果两个链表有公共结点,那么两个链表用公共的尾部,如果从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。
思路1:利用两个辅助栈。分别把两个链表的节点放入两个栈里,这样两个链表的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的节点是否相同,如果相同,则把栈顶弹出接着比较下一个节点,直到找到最后一个相同的节点。 (时间复杂度O(m+n),空间复杂度O(m+n))
之所以需要用到栈,是因为想同时遍历达到两个栈的尾节点。因为当两个链表长度不同时,如果从头开始遍历,到达尾节点的时间就不一致。
思路2:利用长度关系。第一次遍历求出两个链表的长度,第二次遍历时,就让较长的链表先走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点即为所求。 (时间复杂度O(m+n),不需要额外数据结构)
思路3:利用两个链表的节点和相同。让指向链表1的引用依次指向List1和List2,与此同时,让指向链表2的引用依次指向List2和List1。如果两个链表的长度不相同,但是利用长度和相同,第二次遍历两个引用一定同时相遇。 (非常巧妙!!)
解法1
public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if (pHead1 == null || pHead2 == null) return null; Stack<ListNode> stack1 = new Stack<ListNode>(); Stack<ListNode> stack2 = new Stack<ListNode>(); while (pHead1 != null){ stack1.push(pHead1); pHead1 = pHead1.next; } while (pHead2 != null){ stack2.push(pHead2); pHead2 = pHead2.next; } ListNode res = null; while (!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.peek()){ res = stack1.pop(); stack2.pop(); } return res; } }
解法2
public class Solution { // 利用长度关系 // 要考虑到两个链表没有公共结点的情况!!这样最后要返回null public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if (pHead1 == null || pHead2 == null) return null; // 第一次遍历求出两个链表各自的长度 int len1 = getLength(pHead1); int len2 = getLength(pHead2); int len = len1 - len2; // 长度差 ListNode longList = pHead1; ListNode shortList = pHead2; if (len < 0){ // 说明链表2更长 longList = pHead2; shortList = pHead1; len = -len; } for (int i = 0; i < len; i++) { longList = longList.next; } while (longList != null && longList != shortList){ // 如果没有公共结点,则返回null longList = longList.next; shortList = shortList.next; } return longList; // 没有公共结点刚好返回null } private int getLength(ListNode head){ int len = 0; while (head != null){ head = head.next; len++; } return len; } }
解法3
public class Solution { public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if(pHead1 == null || pHead2 == null) return null; ListNode p1 = pHead1; ListNode p2 = pHead2; while (p1 != p2){ p1 = p1 == null ? pHead2 : p1.next; p2 = p2 == null ? pHead1 : p2.next; } return p1; } }
Note:
长度相同有公共结点,第一次就遍历到;没有公共结点,走到尾部NULL相遇,返回NULL
长度不同有公共结点,第一遍差值就出来了,第二遍一起到公共结点;没有公共,一起到结尾NULL。