链表相交等相关问题java - 左神算法基础课04 - Kaiqisan

2023-11-17

大家好,都吃晚饭了吗?我是Kaiqisan,是一个已经走出社恐的一般生徒,今天讲讲我至今碰到的最变态的链表题。

问题

单链表两个单链表可能有环,可能无环,判断两个链表是否存在相交,如果有相交,返回其中一个交点
要求: 时间复杂度 O(m + n) 空间复杂度 O(1)(暗示不能使用hash表)

思路

首先把所有的情况分出来,然后找出规律,分别解决(因为所有的情况都是可以罗列的)

首先要考虑到链表的特殊性,它只有一个next属性,所以每一个节点都只有一个箭头

先考虑两个链表分离的情况

  • 第一种:两个都是无环的

在这里插入图片描述

  • 第二种:一个有环一个无环
    在这里插入图片描述

  • 第三种:两个都是有环的
    在这里插入图片描述
    再考虑两个链表有相交的情况

  • 第四种:两个都是无环的

在这里插入图片描述

  • 第五种:一个有环一个无环
    (这里根据交点位置,分了两种情况)
    在这里插入图片描述
    在这里插入图片描述

判断完所有的情况之后开始解题

我们可以先从两个头结点开始,从头到尾遍历,

  • 如果最终走到了结尾,(出现了tempNode == null),就是情况4情况4,这个时候可以再让两个链表从头走到尾,统计步数,a, b (a > b),然后再让长链表先走 (a - b)步,接下来短链表开始走,每走一步判断地址值是否相等,如果有相等的,就存在相交点,如果走到了终点都没有的话就没有相交点。

  • 如果两个都没有走到结尾(使用快慢指针判断),那就是情况3情况5的两种情况(一共三种情况)

当两个链表都没有走到结尾的时候会返回一个loop节点(就是循环开始的节点)

在这里插入图片描述

  • 如果此时出现两个loop节点都相同的时候,就必然是情况5的后一种

  • 如果两个loop节点都不一样的话就是情况5的前一种以及情况3

  • 剩下就只有情况2,直接返回null

然后是具体思路

    1. 关键在于寻找loop循环节点

从头结点开始使用快慢指针,找到第一个相交的点(因为最后它们都会在一个环里面,所以这就变成了一个追及问题)。然后慢指针记录交点,快指针回到头结点,开始和慢指针一个速度前进,如果两个指针相遇,这个相遇的节点必然是交点,如果有一个指针走向终点,就没有loop节点。

现在我们从追记问题的总距离这里来解释为什么后面说 两个指针相遇,这个相遇的节点必然是交点
在这里插入图片描述
我们看出快指针比慢指针多走一个环,现在我们假设快指针的速度为2个节点 / 秒,慢指针的速度为1个节点 / 秒,求两个节点的相交地点。
现在我们假设链表长 len,环周长为 a
慢节点走过n,那么快节点走过2n

n + a = 2n
a = n
所以慢节点走过一个环的周长的距离a,到达loop节点处还有 len - a距离,
然后让快节点回到起点和慢节点一个速度开始往下走,快节点也是需要走 len - a距离才可以到loop节点处
所以
快慢节点最终必然会在loop节点处相交

    1. 在没有loop节点的时候找交点

我们先分别让两个指针a, b分别从head1 head2开始遍历,得分别出两个距离 m 和 n,比较两个距离大小
现在假设m > n ,
接下来我们让两个指针分别回到各自的头结点,先让a指针先走 m - n 步,然后b指针才开始起步,直到两个指针指向同一个地址(交汇了),第一个交汇的指针就是交点

在这里插入图片描述

现在咱来具体分析下步骤

假设两个指针在第一次遍历走过的共同的路程为x(图中绿色路径),以下简称后半段,也简称他们路径交汇之前的路径为前半段。
在这里插入图片描述
那么在两个节点走前半段的路径分别为 n-x m-x
那么
两个前半段路径之差为m - n
所以在第二次遍历的时候先让b指针先走m - n长度,然后再a, b指针一起走,只需要走n个距离就会在交点交汇,
这个交汇点就是两个链表的交点

PS:情况5的第二种也可以使用上面的思路来解决

    1. 在两个loop节点的时候找交点

这个只要返回其中一个交点就可以了

为了排除情况3
需要判断loop1节点是否可以走到loop2节点,如果从loop1节点开始转圈遍历的时候,在回到loop1之前没有碰到loop2节点,那就是情况3
反之
就是情况5的第一种

代码

	static LinkList doJudge(LinkList head1, LinkList head2) {
        if (head1 == null || head2 == null) {
            return null;
        }

        LinkList loop1 = getLoopNode(head1);
        LinkList loop2 = getLoopNode(head2);

        // 俩都无环的情况,判断是相交还是不相交,如果相交返回相交节点,不相交返回null
        if (loop1 == null && loop2 == null) {
            return noLoop(head1, head2);
        }

        // 一个有环一个无环的情况,且必然相交,找交点
        if (loop1 != null && loop2 != null) {
            return bothLoop(head1, head2, loop1, loop2);
        }

        // 一个有环一个无环不相交的情况必然无交点,所以返回null
        return null;
    }

    static LinkList getLoopNode(LinkList head) {
        if (head == null || head.next == null || head.next.next == null) {
            return null;
        }

        // 快慢指针打大发好
        LinkList slow = head.next;
        LinkList fast = head.next.next;
        // 考虑到结点很短,无法组成环(两个以下的节点)
        while (fast != slow) {
            if (fast.next == null || fast.next.next == null) {
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        fast = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

    static LinkList noLoop(LinkList head1, LinkList head2) {
        int n = 0;
        LinkList temp1 = head1;
        LinkList temp2 = head2;

        // 判断从头结点开始走向尾节点要的步数
        // 然后找出差值

        // 不要走到头,到最后一个节点停下以便判断节点是否相交
        while (temp1.next != null) {
            n++;
            temp1 = temp1.next;
        }

        while (temp2.next != null) {
            n--;
            temp2 = temp2.next;
        }

        if (temp1 != temp2) {
            return null;
        }

        temp1 = n > 0 ? head1 : head2;
        temp2 = temp1 == head1 ? head2 : head1;
        n = Math.abs(n);
        while (n != 0) {
            n--;
            temp1 = temp1.next;
        }
        while (temp1 != temp2) {
            temp1 = temp1.next;
            temp2 = temp2.next;
        }
        return temp1;
    }

    static LinkList bothLoop(LinkList head1, LinkList head2, LinkList loop1, LinkList loop2) {
        LinkList temp1 = null;
        LinkList temp2 = null;
        // 和情况3一样,只不过最后的终点只是到loop结点
        if (loop1 == loop2) {
            temp1 = head1;
            temp2 = head2;
            int n = 0;
            while (temp1 != loop1) {
                n++;
                temp1 = temp1.next;
            }
            while (temp2 != loop1) {
                n--;
                temp2 = temp2.next;
            }

            temp1 = n > 0 ? head1 : head2;
            temp2 = temp1 == head1 ? head2 : head1;
            n = Math.abs(n);
            while (n != 0) {
                n--;
                temp1 = temp1.next;
            }
            while (temp1 != temp2) {
                temp1 = temp1.next;
                temp2 = temp2.next;
            }
            return temp1;
        } else {
            temp1 = loop1.next;
            // 转一圈
            while (temp1 != loop1) {
                // 如果遇到loop2就返回
                if (temp1 == loop2) {
                    return loop1;
                }
                temp1 = temp1.next;
            }
            return null;
        }
    }

总结

还是挺复杂的,会了这道题之后几乎就可以斩杀大部分的链表题目了!(反正以后的链表题我都用java来耍了)
代码很多,但是如果您很熟悉链表的话,就把上面的代码分模块来看,拆分之后就会变得容易很多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链表相交等相关问题java - 左神算法基础课04 - Kaiqisan 的相关文章

随机推荐

  • PyTorch的官方bug:torch.optim.lr_scheduler.CosineAnnealingWarmRestarts

    torch optim lr scheduler CosineAnnealingWarmRestarts 低版本 如torch1 7 1 指定last epoch参数时报错 已有人反馈指出 升级torch1 11 0可以解决该问题 升级之后
  • Python数据可视化——图型参数介绍

    前言 利用Python 绘制常见的统计图形 例如条形 图 饼图 直方图 折线图 散点图等 通过这些常用图形的展现 将 复杂的数据简单化 这些图形的绘制可以通过matplotlib 模块 pandas 模 块或者 seaborn 模块实现 饼
  • java 垃圾回收 sys_深入理解Java虚拟机学习笔记2.1-G1垃圾回收

    G1 GC是Jdk7的新特性之一 Jdk7 版本都可以自主配置G1作为JVM GC选项 作为JVM GC算法的一次重大升级 DK7u后G1已相对稳定 且未来计划替代CMS 所以有必要深入了解下 不同于其他的分代回收算法 G1将堆空间划分成了
  • springmvc中的resolveView(视图解析器)

    视图解析器接口只有一个方法 就是根据名称解析出视图信息 一个视图对象View 采用的是模板模式 抽象模板类 AbstractCachingViewResolver 主要处理缓存 如果视图对象在缓存中有 则从缓存中取 如果没有则创建 publ
  • 整理最全的图床集合——三千图床

    2021 09 25 更新 去除部分图床 添加新的图床 优化排版 引言 古有弱水三千 今有三千图床 勿埋我心 图床一般是指储存图片的服务器 有国内和国外之分 国外的图床由于有空间距离等因素决定访问速度很慢影响图片显示速度 国内也分为单线空间
  • remote: HTTP Basic: Access deniedfatal: Authentication failed for ‘xxxxx‘的问题解决

    在没有修改git密码的情况下 使用vs code推送代码 总是会报错 remote HTTP Basic Access denied fatal Authentication failed for xxxxxxxx git仓库地址 网上试了
  • YOLOV7开源代码讲解--训练参数解释

    目录 训练参数说明 weights cfg data hpy epoch batch size img size rect resume nosave notest noautoanchor evolve bucket cach image
  • 【Basis】狄利克雷分布

    初次看狄利克雷分布 比较懵 主要是它有很多先行知识 所以我先介绍狄利克雷分布用到的多项式分布 gamma 函数 beta分布 然后再介绍狄利克雷分布 参考文献见文章末 目录 一 多项式分布 multinomial distribution
  • 仅仅是一张照片就是不能刷脸支付的

    科技改变未来并不是一句口号 就拿买东西来讲 以前人们都是一手交钱一手交货 拿到大额的纸币 还要验真假 而现在移动支付成为主要付款方式 只要一部手机 扫一扫就能付款 一开始也有很多人不习惯手机支付 因为觉得没有现金实在 整天就是一堆数字转来转
  • 解决TypeError: 'function' object is not subscriptable

    一 解决问题 在tensorflow中使用零矩阵初始化变量的时候出现的该异常 TypeError function object is not subscriptable 二 解决方法 问题代码如下 bias tf Variable tf
  • 深度学习(9):Inception危险物品检测

    目标 基于Inception网络实现对危险物品检测 将危险物品图片或视频经过图像预处理后输入模型推理 最后将检测结果进行可视化输出 一 原理 Google的Inception网络介绍 Inception为Google开源的CNN模型 至今已
  • Java的变量

    1 Java 变量类型 答 在Java语言中 所有的变量在使用前必须声明 声明变量的基本格式如下 type identifier value identifier value 格式说明 type为Java数据类型 identifier是变量
  • Java实现生成csv文件并导入数据

    一 需求 下载列表 在没有过滤之前下载列表所有数据 点击过滤之后 下载过滤之后对数据 生成csv文件 二 思路 先根据条件 是否过滤了数据 筛选出数据 将数据导入csv文件 生成文件并返回 三 代码实现 1 controller层 文件下载
  • Gbase 8s存储结构简介及空间管理

    Gbase 8s实例可以创建多个dbspace 一个dbspace可以包含多个物理chunk 一个chunk分成多个连续扩展区extent 一个表或者索引占用的空间被称为一个tablespace 一个extent包含多个物理页page 其中
  • 利用多线程来实现一个简单的服务器,来实现处理多个用户的请求

    服务器来实现接受多个客户的请求 并且处理响应 服务器采用了多线程 代码如下服务器 package cn kgc basic tcpthread import java io IOException import java net Serve
  • BERT从零详细解读:如何微调BERT,提升BERT在下游任务中的效果

    a 是句子对的分类任务 b 是单个句子的分类任务 c 是问答任务 d 是序列标注任务 首先我自己最常用的就是 文本分类 序列标注和文本匹配 这四个都是比较简单的 我们来看d 序列标注 其实就是把所有的token输出 做了一个softmax
  • Blender学习笔记(建模#3:点操作)

    建模 3 点操作 点操作 1 点的移动 2 点的滑移 3 点的合并 4 点的倒角 5 顶点连接 点操作 1 点的移动 当要将点在斜面上移动时 直接移动很难顺着斜面移动 这时可以使用法向坐标系 2 点的滑移 基本同线的滑移 3 点的合并 两点
  • AngularJs 的compile, preLink , postlink

    AngularJs 的compile preLink postlink 主要参考文章 1 http www jb51 net article 58229 htm 文章中对这三个概念做了详细的解析 如果你只写了一个link 那么系统会默认是p
  • Burp Suit+Phpstudy+Pikachu搭建Web安全练习环境

    1 软件安全测试工具Burp Suit安装 1 1 社区版 进入官网 Download Burp Suite Community Edition PortSwigger 进行下载安装即可 1 2 专业版 搜索Burp Suit2 0 11从
  • 链表相交等相关问题java - 左神算法基础课04 - Kaiqisan

    大家好 都吃晚饭了吗 我是Kaiqisan 是一个已经走出社恐的一般生徒 今天讲讲我至今碰到的最变态的链表题 问题 单链表两个单链表可能有环 可能无环 判断两个链表是否存在相交 如果有相交 返回其中一个交点 要求 时间复杂度 O m n 空