算法通关村第一关-----链表经典问题之解决两个链表第一个公共子节点问题

问题描述

公共子节点

如图所示,两个链表A和B,头节点已知,存在公共子节点c1,c1的位置和数量是不确定的,要求找到A,B的第一个公共子节点。详见leetcode

方法一 基于哈希和集合实现

方法描述

将其中一个链表存储在哈希或者集合中,遍历另一个链表,判断当前遍历结点是否存在于哈希或者集合中,如存在,即是第一个公共子结点,如遍历结束,仍未找到,则不存在公共子节点

代码实现

public static LinkedNode getIntersectionNode(LinkedNode headA, LinkedNode headB){
        HashSet<LinkedNode> hashSet = new HashSet<LinkedNode>();
        while (headA!=null){
            hashSet.add(headA);
            headA = headA.next;
        }
        while (headB!=null){
            if (hashSet.contains(headB)){
                return headB;
            }
            headB = headB.next;
        }
        return null;
    }

方法二 基于栈实现

方法描述

将两个链表分别压入两个栈中,之后将栈中元素依次出栈,比较是否相同,如相同,记录当前元素,继续遍历,直至不相同之前的最后一个相同元素就是公共子节点,如第一次出栈比较就不相同,说明没有公共子节点

代码实现

public static LinkedNode getIntersectionNode(LinkedNode headA, LinkedNode headB){
        Stack<LinkedNode> stackA = new Stack();
        Stack<LinkedNode> stackB = new Stack();
        while (headA!=null){
            stackA.push(headA);
            headA = headA.next;
        }
        while (headB!=null){
            stackB.push(headB);
            headB = headB.next;
        }
        LinkedNode intersectionNode = null;
        while (stackA.size()>0&& stackB.size()>0){
            if(stackA.peek() == stackB.peek()){
                intersectionNode = stackA.pop();
                stackB.pop();
            }
            else {
                break;
            }
        }
        return intersectionNode;
    }

方法三 基于拼接字符串实现

方法描述

以上图的A、B链表为例

A:a1、a2、c1、c2、c3

B:b1、b2、b3、c1、c2、c3

可以在A之后拼接B,B之后拼接A,

AB:a1、a2、c1、c2、c3、b1、b2、b3、c1、c2、c3

BA:b1、b2、b3、c1、c2、c3、a1、a2、c1、c2、c3

此时可以发现 A与B的第一个公共子节点一定存在于AB、BA自后向前的最后一个相同节点,C1

实际操作过程中的拼接使用指针指向另一个链表即可

代码实现

public static LinkedNode getIntersectionNode(LinkedNode headA, LinkedNode headB){
        LinkedNode iterA = headA;
        LinkedNode iterB = headB;
        if (headA==null||headB==null){
            return null;
        }

        while(iterA != iterB){
            iterA = iterA.next;
            iterB = iterB.next;
            if (iterA == null){
                iterA = headB;
            }
            if (iterB == null){
                iterB = headA;
            }
        }
        return iterA;
    }

方法四 基于差和双指针实现

方法描述

假设A的长度为La,B的长度为Lb,差为|La-Lb|,可以遍历长的链表指针先遍历|La-Lb|,之后两个指针一起遍历,遍历到的第一个相同节点即为第一个公共子节点

代码实现

public static LinkedNode getIntersectionNode4(LinkedNode headA, LinkedNode headB) {
        LinkedNode iterA = headA;
        LinkedNode iterB = headB;
        int la = 0;
        int lb = 0;
        while (iterA != null) {
            la++;
            iterA = iterA.next;
        }
        while (iterB != null) {
            lb++;
            iterB = iterB.next;
        }
        int l = la > lb ? la - lb : lb - la;
        iterA = headA;
        iterB = headB;
        if (la > lb) {
            for (int i = 0; i < l; i++) {
                iterA = iterA.next;
            }
        }
        if (la < lb) {
            for (int i = 0; i < l; i++) {
                iterB = iterB.next;
            }
        }
        while (iterA!=null&&iterB!=null) {
            if (iterA == iterB){
                return iterA;
            }
            iterA = iterA.next;
            iterB = iterB.next;
        }
        return null;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天不coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值