算法通关村第一关|两个链表第一个公共子节点

算法通关村第一关|两个链表第一个公共子节点

题目为剑指 Offer 52. 两个链表的第一个公共节点
Alt

解法一:集合

先将一个链表元素全部存入集合,一边遍历第二个链表一边去集合中比较,如果存在交点一定能检测出来

public 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 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) {
            stackA.push(headB);
            headB = headB.next;
        }

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

解法三:拼接两个字符串

有如下两个链表:
A:a1-a2-c1-c2-c3
B:b1-b2-b3-c1-c2-c3

分别以AB和BA拼接后
AB:a1-a2-c1-c2-c3-b1-b2-b3-c1-c2-c3
BA:b1-b2-b3-c1-c2-c3-a1-a2-c1-c2-c3

可以看到从最后一个c1开始两个链表变成一样了,因此c1就是所要找的交点
图片: Alt
假设AB有交点,我们可以以交点为中心,将AB两个链表分成左右两部分:
LA: a1-a2 RA: c2-c3 LB: b1-b2-b3 RB: c2-c3
RA和RB是一样的,这个时候分别遍历AB和BA从某个位置开始刚好就找到了交点

public ListNode findFirstCommonNodeByCombine(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode tempA = headA;
        ListNode tempB = headB;
        while (tempA != tempB) {
            tempA = tempA.next;
            tempB = tempB.next;
            if (tempA != tempB) {
            //一个链表遍历完了就跳到另一个链表接着遍历
                if (tempA == null) {
                    tempA = headB;
                }
                if (tempB == null) {
                    tempB = headA;
                }
            }
        }
        return tempA;
    }

解法四:差和双指针

先统计出两个链表的长度,当第一次链表遍历完后,长的链表先走|LA-LB|步,然后两个链表同时开始遍历,结点相同时就是所要找的交点

 public  ListNode findFirstCommonNodeBySub(ListNode headA , ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode currentA = headA;
        ListNode currentB = headB;
        int lenA = 0, lenB = 0;
        //分别统计两个链表的长度
        while (currentA != null) {
            lenA++;
            currentA = currentA.next;
        }
        while (currentB != null) {
            lenB++;
            currentB = currentB.next;
        }
        currentA = headA;
        currentB = headB;
        int sub = lenA > lenB ? lenA - lenB : lenB - lenA;
        //长的先走sub步
        if (lenA > lenB) {
            int a = 0;
            while (a < sub) {
                currentA = currentA.next;
                a++;
            }
        }

        if (lenA < lenB) {
            int a = 0;
            while (a < sub) {
                currentB = currentB.next;
                a++;
            }
        }

        //最后同时遍历两个链表
        while (currentA != currentB) {
            currentA = currentA.next;
            currentB = currentB.next;
        }
        return currentA;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值