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

image.png

 思路分析

暴力算法

第一种最容易想到的就是暴力算法,但是时间复杂度为O(n^2)

private static ListNode findCommon(ListNode la, ListNode lb) {
        if (la == null || lb == null) {
            return null;
        }
        ListNode p1 = la;
        ListNode p2 = lb;

        while (p1.next != null) {
            while (p2 != null) {
                if (p2 == p1) {
                    return p2;
                }
                p2 = p2.next;
            }
            p2 = lb;
            p1 = p1.next;
        }
        return null;
    }

HashSet集合

第二种方法是通过HashSet或者HashMap的方法逐一匹配,两次循环即可,时间复杂度为O(n)

先将一个链表存储到Set中,再通过一次遍历另一条链表,在遍历的过程中进行匹配寻找是否有交点

public static ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB) {
        Set<ListNode> set = new HashSet<>();
        while (headA != null) {
            set.add(headA);
            headA = headA.next;
        }

        while (headB != null) {
            if (set.contains(headB))
                return headB;
            headB = headB.next;
        }
        return null;
    }

第三种方法是通过栈的方法实现,先把两个链表分别存进两个栈中,利用栈后进先出的特点从后往前遍历,直到无法相等才结束

 public static ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB) {
        Stack<ListNode> stackA = new Stack();
        Stack<ListNode> stackB = new Stack();
        while (headA != null) {
            stackA.push(headA);
            headA = headA.next;
        }
        while (headB != null) {
            stackB.push(headB);
            headB = headB.next;
        }

        ListNode preNode = null;
        while (stackB.size() > 0 && stackA.size() > 0) {
            if (stackA.peek() == stackB.peek()) {
                preNode = stackA.pop();
                stackB.pop();
            } else {
                break;
            }
        }
        return preNode;
    }

拼接字符串

由于两条链表的长度不一样,无法进行逐一比较,但是将他们分别拼接后最后就可以找到相同结点

image.png

public static ListNode findFirstCommonNodeByCombine(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
            if (p1 != p2) {
                if (p1 == null) {
                    p1 = pHead2;
                }
                if (p2 == null) {
                    p2 = pHead1;
                }
            }
        }
        return p1;
    }

 差和双指针

由于要匹配的链表长度可能不同,所以需要先找出长链表和短链表

让长链表先走他们长度的差值,然后两个指针就可以进行逐一匹配了

public static ListNode findFirstCommonNodeBySub(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode current1 = pHead1;
        ListNode current2 = pHead2;
        int l1 = 0, l2 = 0;
        while (current1 != null) {
            current1 = current1.next;
            l1++;
        }

        while (current2 != null) {
            current2 = current2.next;
            l2++;
        }
        current1 = pHead1;
        current2 = pHead2;

        int sub = l1 > l2 ? l1 - l2 : l2 - l1;

        if (l1 > l2) {
            int a = 0;
            while (a < sub) {
                current1 = current1.next;
                a++;
            }
        }

        if (l1 < l2) {
            int a = 0;
            while (a < sub) {
                current2 = current2.next;
                a++;
            }
        }

        while (current2 != current1) {
            current2 = current2.next;
            current1 = current1.next;
        }

        return current1;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值