美文网首页算法相关
编程之美-判断两个链表是否相交 (涵其扩展问题)

编程之美-判断两个链表是否相交 (涵其扩展问题)

作者: HITMiner | 来源:发表于2017-08-11 17:09 被阅读62次

问题定义

两个单向链表的头指针,两个链表都可能带环
1: 判断这两个链表是否相交
2: 如果相交,给出他们相交的第一个节点。

无环情况

判断链表是否相交

单链表相交,意味着相交结点具有相同的内存地址,且相交结点后的所有结点是两个链表共有的。
方法一:


Paste_Image.png

如果两条单链表相交,则将链表B,连接到链表A后面,如图所示(上面的链表是A,下面的链表是B),会形成环路,且链表B的表头一定在环上。因此我们只需要从链表B开始遍历,如果可以回到链表B的头结点,则说明两条链表相交。
时间复杂度:O(len(A)+len(B))
代码如下:

// 结点
static class ListNode{
        int value;
        ListNode next;
    }
static boolean isIntersect1(ListNode h1, ListNode h2){
        boolean isinter = false;
        ListNode p1 = h1, p2 = h2;
        if(p1==null || h2==null) return false;
        // find the end node of list p1
        while(p1.next != null) p1 = p1.next;
        
        // append list p2 on the tail of p1
        p1.next = p2;
        
        // enumerate list p2 from its header
        while(p2 != null){
            if(p2 == h2) {
                isinter = true;
                break;
            }
            p2 = p2.next;
        }

        return isinter;
    }

方法二:
单链表相交,意味着相交结点具有相同的内存地址,且相交结点后的所有结点是两个链表共有的。因此如果两个链表相交,则最后一个节点肯定是相同的,因此只需要判断两个链表的最优一个节点是否相同。
时间复杂度: O(len(A)+len(B))

代码如下:

static boolean isIntersect2(ListNode h1, ListNode h2){
        ListNode p1 = h1, p2 = h2;
        if(p1==null || h2==null) return false;
        ListNode last1 = p1;
        while(p1.next != null){
            last1 = p1;
            p1 = p1.next;
        }
        ListNode last2 = p2;
        while (p2.next != null){
            last1 = p2;
            p2 = p2.next;
        }
        if(last1==last2){
            return true;
        }else return false;

    }

寻找链表的第一个交点

先让计算链表的长度,让最长的链表A先走 len(A)-len(B)步,然后两个链表一起走,第一个相交点,即为所求的点。

static ListNode findFisrtCrossNode(ListNode h1, ListNode h2){
        int lenA = len(h1);
        int lenB = len(h2);
        ListNode p1 = h1, p2 = h2;
        ListNode tmp = null;
        if(lenA > lenB) tmp = p1;
        else tmp = p2;
        for(int i=0; i<Math.abs(lenA-lenB); ++i){
            tmp = tmp.next;
        }
        if(lenA > lenB) p1=tmp;
        else p2 = tmp;
        
        while(p1!=null && p2!=null){
            if(p1==p2) return p1;
            p1 = p1.next;
            p2 = p2.next;
        }
        return null;
    }
static int len(ListNode h){
        int clen = 0;
        ListNode p = h;
        while (p!=null){
            p = p.next;
            ++clen;
        }
        return clen;
    }

有环情况

判断链表是否有环

追逐法:
设置两个指针 fast, slow,将其初始化为链表的头结点;然后两个节点同时向前移动,fast一次移动2步,slow一次移动一步。如果存在环,fast指针和slow指针一定相遇。

static boolean hasCycle(ListNode h){
        ListNode fast=h, slow=h;

        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow && slow!=null){
                return true;
            }
        }
        return false;
 }

寻找环在链表上的入口点

Paste_Image.png
当fast与slow相遇时,假设slow在环内循环了n次,fast在环内循环了m次,显然m>n。
如上图所示,当slow指针和fast直接相遇时(定义此时的节点为相遇结点),设slow指针走过的步长s, 那么根据fast指针的定义,其走过的步长为2s,则2s=a + n(x+y); s = a+m(x+y)
2s-s = (n-m)(x+y) = s = a+m(x+y)
a = (n-2m-1)(x+y)+y; (n-2m-1是整数)
该公式表明:从链表头和相遇点分别设一个指针,每次各走一步,这两个指针必定相遇,且相遇的第一个点为环入口点。

代码如下:

static ListNode findCycleEntry(ListNode h){
        ListNode fast=h, slow=h;
        ListNode meetNode = null;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow && slow!=null){
                meetNode = slow;
                break;
            }
        }
        ListNode p = h;
        while(p!=null && meetNode!=null){
            if(p==meetNode){
                return p;
            }
            p = p.next;
            meetNode = meetNode.next;
        }
        return null;
    }

找出带环的两条链表相交的第一个节点

分两种情况:
1、只有一条链表带环,此时两条链表不可能相交;否则,由于相交结点后的所有结点由两条链表共享,因此导致另一条不带环的链表却出现环,导出相悖的结论。
2、两条链表都带环。如果两条链表相交,则他们共享同一个环!

Paste_Image.png

带环链表相交,如图所示,存在两种情况:
1、交点在环中
2、交点不在环中

参考文献中对该问题的解决办法是首先找两个链表的相遇点,但由于相遇点值存在于环中(利用fast,slow指针的方式得到的相遇点),因此其方法不能解决交点不在环中的情况。

解决方法
第一步:分别找出两个链表的环入口点pos1, pos2;
第二步:如果pos1==pos2, 属于第二种情况:交点不在环中。然后以pos1作为两条链表的终点,利用求不带环单链表交点的方法求出交点。
第三步:如果pos1!=pos2, 从pos1开始遍历环中的节点,如果没有发现有节点与pos2相等,则说明两条链表没有交点,否则,存在交点
第四步:分别以pos1和pos2作为终止节点,用求不带环单链表交点的方法求解。其中,必然一个有解,一个无解。取有解的那一组作为我们的答案。

参考文章:

http://blog.csdn.net/linyunzju/article/details/7753548

相关文章

  • 编程之美-判断两个链表是否相交 (涵其扩展问题)

    问题定义 两个单向链表的头指针,两个链表都可能带环1: 判断这两个链表是否相交2: 如果相交,给出他们相交的第一个...

  • 链表相交的问题(java)

    判断两个无环链表是否相交首先我们要知道相交是什么概念两个链表相交.png现在大家都知道了,两个链表相交,则两个链表...

  • 单链表的就地逆置--java实现(含头节点和不包含头节点)

    前沿:链表是面试中经常问道的知识点,比如链表反转,就地反转,判断单链表是否相交,判断链表是否有环等都是常问的问题....

  • 链表--链表相交 leetcode面试题 02.07

    题目 给定两个链表,判断两个链表是否相交,如果相交返回相交的交点,否则返回空结点。 思路 暴破法采用双循环,从第一...

  • 链表相交问题

    判断两个单向链表是否相交,并找出他们的交点。这个问题我们分三种情况讨论: 一. 两个链表都不存在环 问题思路: ...

  • 链表小题目

    如何判断两条单向链表是否相交,以及相交节点 同时遍历两个链表,求出长度差,然后长的链表走完 N次以后,短链表再开始...

  • 编程判断两个链表是否相交

    给出两个单向链表的头指针,而两个链表都可能带环,判断这两个链表是否相交,并且给出他们相交的第一个节点 参考 1)判...

  • 单链表相交判断

    给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回fal...

  • 有环单链表相交判断

    如何判断两个有环单链表是否相交?相交的话返回true,不想交的话返回false。如果两个链表长度分别为N和M,请做...

  • 判断两个单链表是否相交及找到第一个交点

    题目:给两个单链表,如何判断两个单链表是否相交?若相交,则找出第一个相交的节点。这道题的思路和解法有很多,在这把这...

网友评论

    本文标题:编程之美-判断两个链表是否相交 (涵其扩展问题)

    本文链接:https://www.haomeiwen.com/subject/dtalrxtx.html