[剑指offer 刷题52] - 两个链表的第一个公共节点

题目[题目及部分解法来源于力扣]

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

在这里插入图片描述


solution one:
先遍历两个链表获得二者长度,如果二者长度不等,且二者长度相差n,则前n个节点一定不存在相交的可能。所以,从n+1个节点进行比较,如果指向相同则返回,无相交则返回null。
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) return null;
        ListNode temp1 = headA;
        ListNode temp2 = headB;
        int counter1 = 0;
        int counter2 = 0;
        //获取二者长度
        while(temp1 != null){
            ++counter1;
            temp1 = temp1.next;
        }
        while(temp2 != null){
            ++counter2;
            temp2 = temp2.next;
        }
        //算出二者长度差,从第n+1个节点开始比较
        temp1 = headA;
        temp2 = headB;
        if(counter1 > counter2){
            int distance = counter1 - counter2;
            while(distance > 0){
                temp1 = temp1.next;
                --distance;
            }
            while(temp1 != null){
                if(temp1 == temp2) return temp1;
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
        }
        else if(counter1 < counter2){
            int distance = counter2 - counter1;
            while(distance > 0){
                temp2 = temp2.next;
                --distance;
            }
            while(temp2 != null){
                if(temp2 == temp1) return temp2;
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
        }else if(counter1 == counter2){
            while(temp1 != null){
                if(temp1 == temp2) return temp1;
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
        }
        return null;
    }

或者

   public ListNode getIntersectionNode1(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) return null;
        ListNode temp1 = headA;
        ListNode temp2 = headB;
        int counter1 = 0;
        int counter2 = 0;
        while(temp1 != null){
            ++counter1;
            temp1 = temp1.next;
        }
        while(temp2 != null){
            ++counter2;
            temp2 = temp2.next;
        }
        temp1 = headA;
        temp2 = headB;
        if(counter1 == counter2)
        {
            while(temp1 != null){
                if(temp1 == temp2) return temp1;
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
        }
        else{
            temp1 = counter1 > counter2 ? headA : headB;
            temp2 = counter1 < counter2 ? headA : headB;
            int distance = Math.abs(counter1 - counter2);
            while(distance > 0){
                temp1 = temp1.next;
                --distance;
            }
            while(temp1 != null){
                if(temp1 == temp2) return temp1;
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
        }
        return null;
    }
solution two:
利用哈希集合来存储链表A的节点,由于哈希集合存储元素不相同,故只需要看链表B中节点是否在链表A中出现即可。
 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Set<ListNode> set = new HashSet<ListNode>();
        ListNode temp = headA;
        while(temp != null){
            set.add(temp);
            temp = temp.next;
        }
        temp = headB;
        while(temp != null){
            if(set.contains(temp)){
                return temp;
            }  
            temp = temp.next;
        }
        return null;
    }
solution three:
方法三:设  [第一个公共节点] 为node,链表headA的节点数量为a,链表headB 的节点数为b,两个链表的公共尾部的节点数量为c,则有:
  • 头节点 headA 到node前,共有a - c个节点;
  • 头节点 headB 到node前,共有b - c个节点;
    在这里插入图片描述

考虑构建两个节点指针 A​ , B 分别指向两链表头节点 headA , headB ,做如下操作:

指针 A 先遍历完链表 headA ,再开始遍历链表 headB ,当走到 node 时,共走步数为:a + (b - c)
指针 B 先遍历完链表 headB ,再开始遍历链表 headA ,当走到 node 时,共走步数为:b + (a - c)

如下式所示,此时指针 A , B 重合,并有两种情况: a + (b - c) = b + (a - c)

若两链表 有 公共尾部 (即 c > 0c>0 ) :指针 A , B 同时指向「第一个公共节点」node 。
若两链表 无 公共尾部 (即 c = 0 ) :指针 A , B 同时指向 null 。
因此返回 A 即可。

        ListNode A = headA, B = headB;
        while (A != B) {
            A = A != null ? A.next : headB;
            B = B != null ? B.next : headA;
        }
        return A;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值