IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Day6 链表-判断相交 -> 正文阅读

[数据结构与算法]Day6 链表-判断相交

链表相交

今天是链表的比较难的一个算法,判断两个链表第一个相交的位置在哪,如果有相交返回相交的那个节点;如果没有相交则返回空。

首先,我们要把判断分成几个情况。

一、有环和无环

显然,有环和无环两种情况,对链表判断相交与否肯定有影响。如果有环就返回环的入口,如果没环就返空。那么我们要先判断两个链表是否有环。要判断有环和无环我们依旧可以使用快慢指针。

让快指针和慢指针一起走,如果快指针能走到null,那么显然没有环,如果快指针和慢指针最终相遇了。

复杂的算法证明:当慢指针走到环的入口是,慢指针走了环外长度 x 步,而快指针走了x + n圈y长度的环的步数+d环内多走了几步?。那么 x ==? ny + d,因为快指针比慢指针在环内多走了d步。因此,快指针要再走y-d步才能和慢指针相遇,又因为快指针一次走两步,所以快指针在环内还要再走 2(y-d)步;那么快指针再次追上慢指针是在 2(y-d) + d = 2y -d 也就是快指针是走了2圈退d步,也就是在环入口节点往逆环方向走d步。

可以发现,这个时候快指针的位置慢指针刚进环时候的快指针当时的位置是对称的。

那么,只要在快慢指针相遇时,把快指针放回head节点,再两个指针一起动,此时两个指针都一次走一格。那么此时快指针走了:x步, 由前面x == ny + d 会发现,此时慢指针恰好走了n圈,并再走了d步回到入口。

结论:快慢指针从head一起出发,当两个指针在环内相交时,把快指针再指向头节点。再让两个指针以一次一步同速走,那么两个指针再次相遇的地点就是环的入口

证明的链接

方法代码:

     //获得链表环的入环节点,如果没环返回空
        static Node GetLoopNode(Node head)
        {
            if(head ==null || head.next ==null || head.next.next == null)
            {
                return null;
            }
            Node f = head;
            Node s = head;
            f = f.next.next;
            s = s.next;
            //一直走直到指针相遇
            while (s != f)
            {
                //如果快指针走到null就返回null表示无环
                if(f.next == null || f.next.next == null)
                {
                    return null;
                }
                s = s.next;
                f = f.next.next;
            }
            //让快指针回到头节点
            f = head;
            //继续遍历,两个指针一定会在环的入环点相遇
            while (s != f)
            {
                s = s.next;
                f = f.next;
            }
            return s; 
        }

二、都有环和都没环

很显然,一个有环一个没环是不可能有交点的,直接返回空

那么接下来讨论都有环和都没环的情况:

1)都没环

都没环意味着两个链表都能走到最后,也就是我们能算得出来两个链表的长度和最后一位。

如果练个链表相交,两个链表必然会有公共部分,设链表1的前半部分长度是a,链表2是b,两个后半部分长度都是是c

那么显然,a+c - (b+c)就是两个链表长度的差值绝对值,要想算出两个链表的交点只需要让长的链表先走差值的部分再让两个链表一起走,那么两个链表必然会同时走到第一个交点,就假设,a是5,b是3,c是8,那么如果a先走了2步再两个一起走3步,必然会同时走到两个的交点,只要判断指针是否一样就可以知道哪个点是第一个交点了。

如果两个链表没有交点,这个只要在计算两个链表长度的时候比对一下最后一个节点的指针是否相等,如果不等一定没有交点。

代码:

 //获得无环链表的第一个交点
        static Node GetNoLoopNode(Node head1,Node head2)
        {
            Node n1 = head1;
            Node n2 = head2;
            int n = 0;
            while (n1.next != null)
            {
                n++;
                n1 = n1.next;
            }
            while (n2.next != null)
            {
                n--;
                n2 = n2.next;
            }
            //如果两个指针走到尾不相等那么不可能相交
            if(n1 != n2)
            {
                return null;
            }
            n1 = n > 0 ? head1 : head2;
            n2 = n1 == head1 ? head2 : head1;
            n = Math.Abs(n);
            while (n != 0)
            {
                n1 = n1.next;
                n--;
            }
            while (n1 != n2)
            {
                n1 = n1.next;
                n2 = n2.next;
            }
            return n1;
        }

2)都有环

都有环的话,如果有交点分成俩情况:

1、交点在环外。因为我们已经知道两个链表都有环,那么我们只要用前面的函数来分别得到两个链表入环的点。既然点在环外,那么两个链表入环点是一样的,我们只要吧这个入环点当成两个链表的终点(把两个有环链表当成无环的来看,终点变成入环点)。这样的话,我们只要按照两个都无环的情况来处理就好。

2、交点在环内。我们只要让两个链表的其中一个在loop1直接继续走,如果走一圈环而没有碰到另一个链表的loop2,那么两个链表没交点,如果走了一圈碰到了loop2则表示有交点并返回那个点。

代码:

    //获得有环链表的第一个交点
        static Node GetBothLoopNode(Node head1,Node loop1, Node head2,Node loop2)
        {
            Node n1 = null;
            Node n2 = null;
            //当两个链表的入环点是一样时 判断在哪入的环
            if (loop1 == loop2)
            {
                n1 = head1;
                n2 = head2;
                //n来记录两个链表从head到入环的走的长度的差
                int n = 0;
                while (n1.next != loop1)
                {
                    n++;
                    n1 = n1.next;
                }
                while (n2.next != loop2)
                {
                    n--;
                    n2 = n2.next;
                }
                //让n1代表长的一个链表
                n1 = n > 0 ? head1 : head2;
                n2 = n1 == head1 ? head2 : head1;
                n = Math.Abs(n);
                //让长的链表先走n的距离 再一起走 什么时候指针相同,那就是第一个交点
                while (n != 0)
                {
                    n--;
                    n1 = n1.next;
                }
                while (n1 != n2)
                {
                    n1 = n1.next;
                    n2 = n2.next;
                }
                return n1;
            }
            else
            {
                //让n1指向loop1的下一位,然后持续遍历直到n1走到loop2
                n1 = loop1.next;
                while(n1 != loop1)
                {
                    if(n1 == loop2)
                    {
                        return n1;
                    }
                    n1 = n1.next;
                }
                return null;
            }
            return null;
        }

下面是整合之后的函数代码:

     //获得两个链表的第一个交点 没有就返回空
        static Node GetIntersectNode(Node head1, Node head2)
        {
            if(head1 == null || head2 == null)
            {
                return null;
            }
            Node loop1 = GetLoopNode(head1);
            Node loop2 = GetLoopNode(head2);
            if(loop1 == null && loop2 == null)
            {
                return GetNoLoopNode(head1, head2);
            }
            if(loop1 != null && loop2 != null)
            {
                return GetBothLoopNode(head1,loop1, head2,loop2);
            }
            return null;
        }


昨天国庆,比较摸嘿嘿!

如果有写的不好的或者有错的地方、望指正,如果我的自我监督学习记录有帮到你的话就好!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:18:25  更:2021-10-03 17:18:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 11:49:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码