剑指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。

 

posted @ 2020-08-21 16:53  不学无墅_NKer  阅读(139)  评论(0编辑  收藏  举报