编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 01.单链表创建和使用
  • 02.双链表创建和使用
  • 03.循环链表创建和使用
  • 04.用单向链表实现栈
  • 05.合并两个排序的链表
  • 06.将单链表反转
  • 07.判断单链表是否有环
  • 08.取出有环链表中环的长度
  • 09.链表中环的入口结点
  • 10.两个链表第一个公共结点
  • 11.删除链表的倒数第N个节点
  • 12.获得单链表倒数第k个结点
  • 13.单链表中取出环的起始点
  • 14.两个单链表相交第一个交点
  • 15.复杂链表的复制
  • 16.求单链表中节点的个数
  • 17.从尾到头打印链表

10.两个链表第一个公共结点

目录介绍

  • 01.题目要求
  • 02.问题分析
  • 03.实例代码

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!所有博客陆续更新到GitHub上!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

01.题目要求

  • 问题如下所示:
    • 输入两个链表,找出它们的第一个公共结点。
  • 示例 :

02.问题分析

第一种:直接法 在第一个链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了它们的公共结点。如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度是O(mn) 。

第二种:使用栈 所以两个有公共结点而部分重舍的链衰,拓扑形状看起来像一个Y, 而不可能像X(如图5.3 所示)。

这里写图片描述
这里写图片描述

经过分析我们发现,如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。如果我们从两个链衰的尾部开始往前比较,最后一个相同的结点就是我们要找的结点。 在上述思路中,我们需要用两个辅助钱。如果链表的长度分别为m 和n,那么空间复杂度是O(m+n)。这种思路的时间复杂度也是O(m+n)。和最开始的蛮力法相比,时间效率得到了提高,相当于是用空间消耗换取了时间效率。

第三种:先行法 在图5.3 的两个链表中,我们可以先遍历一次得到它们的长度分别为5 和4, 也就是较长的链表与较短的链表相比多一个结点。第二次先在长的链表上走1 步,到达结点2。接下来分别从结点2 和结点4 出发同时遍历两个结点, 直到找到它们第一个相同的结点6,这就是我们想要的结果。 第三种思路和第二种思路相比,时间复杂度都一样, 但我们不再需要辅助的拢,因此提高了空间效率。

03.实例代码

  • 如下所示
    public class Test {
        /**
         * 链表结点类
         */
        private static class ListNode {
            int val;
            ListNode next;
    
            public ListNode() {
    
            }
    
            public ListNode(int val) {
                this.val = val;
            }
    
            @Override
            public String toString() {
                return val + "";
            }
        }
    
        /**
         * 找两个结点的第一个公共结点,如果没有找到返回null,方法比较好,考虑了两个链表中有null的情况
         *
         * @param head1 第一个链表
         * @param head2 第二个链表
         * @return 找到的公共结点,没有返回null
         */
        public static ListNode findFirstCommonNode(ListNode head1, ListNode head2) {
            int length1 = getListLength(head1);
            int length2 = getListLength(head2);
    
            int diff = length1 - length2;
            ListNode longListHead = head1;
            ListNode shortListHead = head2;
    
            if (diff < 0) {
                longListHead = head2;
                shortListHead = head1;
                diff = length2 - length1;
            }
    
            for (int i = 0; i < diff; i++) {
                longListHead = longListHead.next;
            }
    
            while (longListHead != null && shortListHead != null && longListHead != shortListHead) {
                longListHead = longListHead.next;
                shortListHead = shortListHead.next;
            }
    
            // 返回第一个相同的公共结点,如果没有返回null
            return longListHead;
        }
    
        private static int getListLength(ListNode head) {
            int result = 0;
            while (head != null) {
                result++;
                head = head.next;
            }
    
            return result;
        }
    }

其他内容

01.关于博客汇总链接

  • 1.技术博客汇总
  • 2.开源项目汇总
  • 3.生活博客汇总
  • 4.喜马拉雅音频汇总
  • 5.其他汇总

02.关于我的博客

  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yczbj/activities
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
  • 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
贡献者: yangchong211
上一篇
09.链表中环的入口结点
下一篇
11.删除链表的倒数第N个节点