剑指Offer对答如流系列

面试题52:两个链表的第一个公共结点

题目描述

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

链表节点定义如下:

	public class ListNode{
        int val;
        ListNode next = null;
        ListNode(int val) {
            this.val = val;
        }
    }

在这里插入图片描述

问题分析

最直接的手段是暴力法,遍历第一个链表的结点,每到一个结点,就在第二个链表上遍历每个结点,判断是否相等。时间复杂度为O(m*n),效率低,面试中这种解法肯定不会让面试官满意。

我们需要点技巧,我们列举一下吧

方法一:

使用栈:由于公共结点可以从尾部进行判断,所以用两个栈分别放入两个链表中的结点,从尾结点开始出栈比较。时间复杂度O(m+n),空间复杂度O(m+n)。

方法二:

之前我们做过剑指Offer对答如流系列 - 链表中倒数第k个结点

可以利用长度关系:计算两个链表的长度之差,长链表先走相差的步数,之后长短链表同时遍历,找到的第一个相同的结点就是第一个公共结点。

方法三:

之前我们做过剑指Offer对答如流系列 - 链表中环的入口节点

利用两个引用:一个引用顺序遍历list1和list2,另一个引用顺序遍历list2和list1,(这样两引用能够保证最终同时走到尾结点),两个引用找到的第一个相同结点就是第一个公共结点。

问题解答

利用长度关系的解法:

public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        
        int length1 = getLength(pHead1);
        int length2 = getLength(pHead2);
        int lengthDif = length1-length2;
        ListNode longList = pHead1;
        ListNode shortList = pHead2;
        
        if(lengthDif<0){
            longList = pHead2;
            shortList = pHead1;
            lengthDif = -lengthDif;
        }
        
        for(int i=0;i<lengthDif;i++) {
            longList = longList.next;
        }
           
        while(longList!=null && longList!=shortList ){
            longList=longList.next;
            shortList=shortList.next;
        }
        return longList;  //没有公共结点刚好是null
    }

    private int getLength(ListNode head){
        int len=0;
        while(head!=null){
            len++;
            head=head.next;
        }
        return len;
    }

利用两个引用的解法

   public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1=pHead1;
        ListNode p2=pHead2;
        while(p1!=p2){
            p1= (p1==null ? pHead2 : p1.next);
            p2= (p2==null ? pHead1 : p2.next);
        }
        return p1;
    }
原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246621.html