《剑指offer》-[第5章:优化时间与空间效率-5.2:时间与空间效率的平衡]-题37:两个链表的第一个公共结点

博客围绕输入两个链表求第一个公共结点的问题展开。先给出边界条件,接着介绍三种解题思路:一是用双指针遍历,时间复杂度O(mn);二是借助两个辅助栈从后往前比较,时间复杂度O(m+n),空间复杂度O(m+n);三是不借助栈,先算长度差,再同步遍历,时间复杂度O(m+n),最后给出代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、问题描述

输入两个链表,求这两个链表的第一个公共结点。

2、解题思路

  • 边界条件:两个链表一个为空或者两个都为空,返回空

  • 思路1:最简单的方法是使用两个指针对这两个链表进行遍历,在第一个指针遍历第一个链表中某个结点的时候,第二个指针遍历整个第二个链表,如果第二个指针遍历的某个结点与第一个指针遍历的结点相等,则该相等的结点为两个链表的第一个公共节点,这种方法的时间复杂度为O(mn)O(mn)O(mn)

  • 分析:如果两个单向链表有公共的结点,那么说明这两个链表从某个结点开始,它们的next指针都指向了同一个结点,但由于是单向链表的结点,每个结点只能有一个后继结点,所以从第一个公共结点之后,两个链表的所有结点都是相同的,如下图所示。
    在这里插入图片描述

  • 结论:从图中可以看出,如果两个链表有公共结点,那么第一个公共结点一定出现在两个链表的末尾。

  • 思路2:根据结论,我们可以从两个链表的最后一个结点开始,依次向前比较,直至找到最后一个相等的结点为止。但是,我们知道,单向链表一般只能从前向后遍历,从后往前遍历怎么实现呢?我们可以通过两个辅助栈实现这一过程,一开始,把这两个链表分别压入两个栈中,然后比较这两个栈的栈顶元素,如果栈顶元素相同,则将两个栈的栈顶元素同时弹出,如果不相同,那么第一个公共结点为上次弹出的元素。这种方法的时间复杂度为O(m+n)O(m+n)O(m+n)(主要是对链表的压栈操作),空间复杂度为O(m+n)O(m+n)O(m+n)(两个栈的大小)。

  • 思路3:其实,我们也可以不借助辅助栈来找到第一个公共结点,该方法的步骤是,先对两个链表分别遍历,获得这两个链表的长度,接着计算这两个链表的长度差k,然后在长链表上先走k步,紧接着在长短链表上同时遍历,找到的第一个相同的结点就是它们的第一个公共结点。这种方法省去了栈的空间开销,时间复杂度为O(m+n)O(m+n)O(m+n)

3、代码实现

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if(pHead1 == null || pHead2 == null){
            return null;
        }

        ListNode common_node = null;
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        int length1 = 0;
        int length2 = 0;

        while (p1 != null){
            length1 += 1;
            p1 = p1.next;
        }
        while (p2 != null){
            length2 += 1;
            p2 = p2.next;
        }
        
        int dis = 0;
        ListNode long_list = null;
        ListNode short_list = null;
        if(length1 < length2){
            dis = length2 - length1;
            short_list = pHead1;
            long_list = pHead2;
        }
        else {
            dis = length1 - length2;
            short_list = pHead2;
            long_list = pHead1;
        }
        int i = 0;
        while (i < dis){
            long_list = long_list.next;
            i += 1;
        }
        while(long_list != null){
            if(long_list.val == short_list.val){
                common_node = long_list;
                break;

            }
            else {
                long_list = long_list.next;
                short_list = short_list.next;

            }
        }
    return common_node;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Albert_YuHan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值