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

文章介绍了四种解决链表公共子节点问题的算法:1)使用哈希集合,遍历一个链表存储节点,再遍历另一个链表检查节点是否存在;2)利用栈,分别将两个链表压栈,比较弹出的节点是否相等;3)拼接字符串,保持两个链表长度相等,相同索引的节点即为公共节点;4)差和双指针,通过调整链表长度使其相等,然后同时遍历。这些方法展示了如何利用数据结构和算法解决编程问题。
摘要由CSDN通过智能技术生成

今天学习一下链表的公共子节点问题

如图所示,有两个链表在某处开始公用子节点,我们的目标是找出开始公用的节点即图片的C1点

 1.哈希集合

看到题目的第一个解题思路应当是最容易想到使用hash,遍历第一个链表存到集合中,然后遍历第二个链表并判断当前元素是否存在于集合中,如果存在则保存这个元素退出遍历

代码实现:

public StudentNode getFirstCommonNode(StudentNode headA,StudentNode headB){
        Set<StudentNode> set = new HashSet<>();
        //遍历headA链表到set集合中
        while (headA!=null){
            set.add(headA);
            headA = headA.next;
        }
        while (headB!=null){
            //判断headB节点是否属于set
            if (set.contains(headB)){
                return headB;
            }
            headB=headB.next;
        }
        return null;
    }

2.使用栈

public StudentNode getFirstCommonNode(StudentNode headA,StudentNode headB){
        //初始化两个栈
        Stack<StudentNode> stackA = new Stack<>();
        Stack<StudentNode> stackB = new Stack<>();
        //将两个链表压入栈中
        while (headA!=null){
            stackA.push(headA);
            headA = headA.next;
        }
        while (headB!=null){
            stackB.push(headB);
            headB = headB.next;
        }
        StudentNode currentNode = null;
        StudentNode popA;
        StudentNode popB;
        while(stackA.size()>0&&stackB.size()>0){
             popA = stackA.pop();
             popB = stackB.pop();
             //取出的节点相等时就赋值给目标节点,直到取出最后一个相等的节点
            if (popA==popB){
                currentNode = popA;
            }else {
                break;
            }
        }
        return currentNode;
    }

3.拼接字符串

在遍历完headA链表时指向headB的头结点,遍历完headB时指向headA头结点,核心思想是保持两个链表的长度相等,这样遍历如果有公共子节点就会出现在两个链表的相同index上。

public  StudentNode getFirstCommonNode(StudentNode headA, StudentNode headB) {
            if (headA == null || headB == null) {
                return null;
            }
            StudentNode currentNodeA = headA;
            StudentNode currentNodeB = headB;
            while (currentNodeA != currentNodeB) {
                currentNodeA = currentNodeA.next;
                currentNodeB = currentNodeB.next;
                在同时到达末尾时null==null,离开循环,不然如果没有公用节点的话会陷入死循环
                if (currentNodeA != currentNodeB) {
                    //headA到末尾时指向headB头结点
                    if (currentNodeA == null) {
                        currentNodeA = headB;
                    }
                    //headB到末尾时指向headA头结点
                    if (currentNodeB == null) {
                        currentNodeB = headA;
                    }
                }
            }
            return currentNodeA;
        } 

4.差和双指针

假设两个链表长度不相同,我们让长度长的那条先遍历,直到剩下长度和另外一条链表长度相等,这样也是保持同时遍历的链表长度相等。

    public  StudentNode getFirstCommonNode(StudentNode headA, StudentNode headB) {
        if (headA==null||headB==null){
            return null;
        }
        StudentNode startNode;
        StudentNode endNode;
        long diff;
        StudentNode headABack = headA;
        StudentNode headBBack = headB;
        long sizeA = 0;
        long sizeB = 0;
        //headA链表长度
        while (headABack!=null){
            headABack=headABack.next;
            sizeA++;
        }
        //headB链表长度
        while (headBBack!=null){
            headBBack=headBBack.next;
            sizeB++;
        }
        //判断从哪个链表开始遍历
        if (sizeA>sizeB){
            startNode=headA;
            endNode = headB;
            diff=sizeA-sizeB;
        }else {
            startNode = headB;
            endNode = headA;
            diff=sizeB-sizeA;
        }
        //长度不相等时
        if (diff>0){
            for (int i = 1; i <=diff ; i++) {
                startNode=startNode.next;
            }
        }
        while (startNode!=endNode ){
            startNode=startNode.next;
            endNode=endNode.next;
        }
        return startNode;
    }

总结:

以上就是解决两个链表相同节点问题的四个解决方式

就像骨头哥讲的那样,我们遇到问题时首先要仔细的想一遍常用的数据结构和算法思想,或许是我们解决问题的第一步!!

常用的数据结构有数组、链表、队、栈、Hash、集合、树、堆。常用的算法思想有查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值