两个单链表相交的系列问题

给定两个单链表的头节点head1,head2,判断两个链表是否相交,若相交返回相交的第一个节点,若不相交则返回null

由于单链表可能无环,也可能有环,因此这个问题可以总划分为三个方面:

  • 判断一个单链表是否有环
  • 判断两个无环链表是否相交
  • 判断两个有环链表是否相交

一个有环链表和一个无环链表是不可能相交的,因为若相交则无环链表一定时有环的

1. 判断一个单链表是否有环,有环则返回第一个相交的节点loop,不相交则返回null。

(1)第一种方法:用哈希表,依次将遍历的节点存入,若有重复的则有环,相反则无环。但这种方法的空间复杂度高,无法达到题目要求。

(2)第二种方法:快慢指针的方法。

​ 1. 遍历节点时,快指针走两步,慢指针走一步。

​ 2. 若快指针到null,则为无环返回null。

​ 3. 若快指针和慢指针相遇,快指针回到head,且之后一次走一步。

​ 4. 快指针和慢指针相遇的节点,为第一个相交的节点loop,返回该节点

代码如下:

public static Node getLoopNode(Node head){
        if(head==null || head.next==null || head.next.next==null){
            return null;
        }
        Node slow = head.next; //慢指针
        Node fast = head.next.next; //快指针
        while (fast!=slow){
            if(fast.next==null ||fast.next.next==null ){
                return null; //无环返回null
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        fast = head; //快指针和慢指针相遇后,快指针回到head
        while (fast != slow){
            fast = fast.next; //快指针一次走一步
            slow = slow.next;
        }
        return fast; //快指针和慢指针相遇的节点,为第一个相交的节点loop,返回该节点
    }
2. 判断两个无环链表是否相交,若相交则返回第一个相交节点,不相交则返回null。

要注意这种情况是不会出现的:在这里插入图片描述

  1. head1遍历到最后一个结点end1,记录长度为len1。head2遍历到最后一个结点end2,记录长度为len2。
  2. 若end1!=end2,则两链表不相交,返回null。
  3. 若相等,则相交。较长的链表先走|len1-len2|步,之后又两链表一起一次走一步,相遇的结点即为相交节点,返回该节点即可

代码如下:

public static Node noLoop(Node head1,Node head2){
        if(head1==null || head2==null){
            return null;
        }
        Node cur1 = head1;
        Node cur2 = head2;
        int n=0;
        while (cur1.next != null){
            n++;
            cur1=cur1.next;
        }
        while (cur2.next != null){
            n--;
            cur2=cur2.next;
        }
        if(cur1!=cur2){
            return null;
        }
        cur1 = n>0 ? head1 : head2;
        cur2 = n>0 ? head2 : head1;
        n = Math.abs(n);
        while (n!=0){
            n--;
            cur1 = cur1.next;
        }
        while (cur1!=cur2){
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return cur1;
    }
3.判断两个有环链表是否相交,若相交则返回第一个节点,若不想交则返回null。

根据1求得的两个链表的第一个入环结点loop1和loop2.

(1)若loop1==loop2,则如下图所示

在这里插入图片描述

我们只需要考虑红线中的链表长度即可,与问题二类似。

(2)若loop1!=loop2,则如下图所示,有两种情况,左边是不相交的,右边是相交的

在这里插入图片描述

我们可以从loop1出发,遍历链表,在再次回到loop1之前,若未遇到loop2则说明是左边的情况,不相交。若遇到loop2,则说明是右边的情况,相交,返回loop1或loop2都可以。

代码如下:

public Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
        Node cur1 = null;
        Node cur2 = null;
        if (loop1 == loop2) {
            cur1 = head1;
            cur2 = head2;
            int n = 0;
            while (cur1.next != loop1) {
                n++;
                cur1 = cur1.next;
            }
            while (cur2.next != loop2) {
                n--;
                cur2 = cur2.next;
            }
            cur1 = n > 0 ? head1 : head2;
            cur2 = n > 0 ? head2 : head1;
            n = Math.abs(n);
            while (n != 0) {
                n--;
                cur1 = cur1.next;
            }
            while (cur1 != cur2) {
                cur1 = cur1.next;
                cur2 = cur2.next;
            }
            return cur1;
        } else {
            cur1 = loop1.next;
            while (cur1 != loop1) {
                if (cur1 == loop2) {
                    return loop1;
                }
                cur1 = cur1.next;
            }
            return null;
        }
    }

整个题目的主方法代码如下:

public 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 noLoop(head1, head2);
        }
        if (loop1 != null && loop2 != null) {
            return bothLoop(head1, loop1, head2, loop2);
        }
        return null;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值