• 算法练习(10)-求2个(可能有环的)单链表的相交节点


    注:题解来自左程云大佬,记录一下
    这个问题可以看做是 算法练习(7)-判断单链表是否有环,以及求环的长度 的升级版,分析:对于单链表而言,如果2个链表能相交,只可能出现下面这几种情况
    链表1 类型 链表2 类型 相交可能性? 备注 图例
    无环 无环  
    无环 有环 × 如果能相交,必然2个都是有环  
    有环 有环    或  
    可以分解成几个小问题:
    1、如何判断链表是有环的?
    /**
     * 如果1个单链表有环,返回入环节点
     *
     * @param head
     * @return 如果有环, 则返回入环节点,否则返回null
     */
    public static LinkNode getLoopEntrance(LinkNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        LinkNode slow = head;
        LinkNode fast = head;
        boolean isLoop = false;
        //先跑一圈, 判断是否有环
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow.equals(fast)) {
                isLoop = true;
                break;
            }
        }
        if (!isLoop) {
            return null;
        }
        //快指针重回头部,再跟慢指针齐步向前走,fast与slow必然相交于入环点(数学上可证明,证明过程略)
        fast = head;
        while (fast.next != null) {
            if (slow.equals(fast)) {
                return slow;
            }
            slow = slow.next;
            fast = fast.next;
        }
        return null;
    }
    

      

    2、如何判断2个无环链表,是否相交?

    /**
     * 返回2个无环链表的相交节点
     *
     * @param head1 链表1的头节点
     * @param head2 链表2的头节点
     * @return 如果相交,则返回相交节点,否则返回null
     */
    public static LinkNode getNoLoopCrossNode(LinkNode head1, LinkNode head2) {
        //思路:先测量各自的长度, 然后找出长度差值
        //第二轮遍历时, 让长度大的链表先走差值步,再2个链表齐步走, 如果有相交,必然在交叉点相遇
        if (head1 == null || head2 == null) {
            return null;
        }
        int size1 = 0, size2 = 0;
        LinkNode h1 = head1, h2 = head2;
        while (h1 != null) {
            size1 += 1;
            h1 = h1.next;
        }
        while (h2 != null) {
            size2 += 1;
            h2 = h2.next;
        }
        int diff = Math.abs(size1 - size2);
        //让h1指向长的链表头
        h1 = size1 >= size2 ? head1 : head2;
        //让h2指向短的链表头
        h2 = h1.equals(head2) ? head1 : head2;
        //长链表先走差值步
        for (int i = 0; i < diff; i++) {
            h1 = h1.next;
        }
        //2个链表再齐步走
        while (h1 != null && h2 != null) {
            if (h1.equals(h2)) {
                return h1;
            }
            h1 = h1.next;
            h2 = h2.next;
        }
        return null;
    }
    

      

    3、如何判断2个有环链表,是否相交?

    /**
     * 判断2个有环单链表是否相交
     *
     * @param entrance1 链表1的入环节点
     * @param entrance2 链表2的入环节点
     * @return 如果相交, 返回相交点
     */
    public static LinkNode getLoopCrossNode(LinkNode entrance1, LinkNode entrance2) {
        if (entrance1 == null || entrance2 == null) {
            return null;
        }
        //2个入环节点相同, 必然相交
        if (entrance1.equals(entrance2)) {
            return entrance1;
        }
        //从入环节点a出发, 一直向前走, 直到再次遇到自己前, 如果路上遇到另1个入环节点b,则a,b肯定在一个环上
        LinkNode n1 = entrance1;
        while (entrance1 != null) {
            if (entrance1.equals(entrance2)) {
                return entrance1;
            }
            entrance1 = entrance1.next;
            if (n1.equals(entrance1)) {
                break;
            }
        }
        return null;
    }
    

      

    综合以上几个小方法, 就能解决该问题:

    /**
     * 如果2个(可能有环的)链表相交,返回相交点
     * @param h1 链表1的头节点
     * @param h2 链表2的头节点
     * @return 如果相交,返回相交节点
     */
    public static LinkNode getCrossNode(LinkNode h1, LinkNode h2) {
        LinkNode entrance1 = getLoopEntrance(h1);
        LinkNode entrance2 = getLoopEntrance(h2);
        if (entrance1 == null && entrance2 == null) {
            //都是无环链表
            return getNoLoopCrossNode(h1, h2);
        }
        //至少1个是有环链表
        return getLoopCrossNode(entrance1, entrance2);
    }
    

      

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    [OpenWRT]判断WDS是否开启
    【cocos2d-js官方文档】一、搭建 Cocos2d-JS 开发环境
    noi Big String 超级字符串
    序列 xulie (2017青岛)
    %%%城市交通费 city //程序超时
    3.密码pasuwado————记第一次超越Candy?
    图论-欧拉回路(邻接链表)
    blue and red ball
    魔方→︿←
    The first DP!
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/15448944.html
Copyright © 2020-2023  润新知