算法面试之链表相交问题

简介

【题目】

在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。

【要求】

如果链表1的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达到O(1)

问题分析

分为以下情况考虑:

1、两个有环链表,若相交,相交点一定为入环点,只需判断两个入环点是否相同即可
2、两个无环链表,只需遍历链表看是否有相同结点即可(程序中实现的方法比较巧妙)
3、一个有环链表和一个无环链表,不可能相交

代码实现

public class IntersectList {
    public static void main(String[] args){
        Node n1=new Node(1);
        Node n2=new Node(2);
        Node n3=new Node(3);
        Node n4=new Node(4);
        Node n5=new Node(5);
        Node n6=new Node(6);
        Node n7=new Node(7);
        Node n8=new Node(8);
        Node n9=new Node(9);
        //测试相同头
        System.out.println(getIntersect(n1,n1));
        System.out.println(getIntersect(n1,n2));
        //测试两个有环
//        n1.next=n2;
//        n2.next=n3;
//        n3.next=n4;
//        n4.next=n2;

//        n6.next=n2;

//        n6.next=n7;
//        n7.next=n8;
//        n8.next=n9;
//        n9.next=n7;
        System.out.println(getIntersect(n1,n6));
        //测试两个无环
//        n1.next=n2;
//        n2.next=n3;
//
//        n6.next=n7;
//        n7.next=n8;

//        n1.next=n2;
//        n2.next=n3;
//
//        n6.next=n2;
        System.out.println(getIntersect(n1,n6));
        //测试一个有环、一个无环
        n1.next=n2;
        n2.next=n3;
        n3.next=n4;
        n4.next=n2;

        n6.next=n7;
        n7.next=n8;
        System.out.println(getIntersect(n1,n6));

    }

    //链表
    public static class Node{
        int data;
        Node next;

        public Node(int data) {
            this.data = data;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "data=" + data +
                    '}';
        }
    }

    //判断链表是否有环,返回入环的结点
    public static Node isRing(Node head){
        if(head==null){
            return null;
        }
        Node quick=head;
        Node low=head;
        while (quick.next!=null&&quick.next.next!=null){
            quick=quick.next.next;
            low=low.next;
            if(quick==low){
                return quick.next;
            }
        }
        return null;
    }

    //获取链表交点
    public static Node getIntersect(Node head1,Node head2){
        if(head1==null||head2==null){
            return null;
        }
        if(head1==head2){
            return head1;
        }
        Node h1=isRing(head1);
        Node h2=isRing(head2);
        //one is ring,another is not ring
        if((h1==null&&h2!=null)||(h1!=null&&h2==null)){
            return null;
        }
        //two are not ring
        if(h1==null&&h2==null){
            return getIntersectNotRing(head1,head2);
        }
        //two are ring
        if(h1!=null&&h2!=null){
            return getIntersectRing(head1,h1,head2,h2);
        }
        return null;
    }

    //两个有环
    public static Node getIntersectRing(Node head1, Node h1, Node head2, Node h2) {
        return h1==h2?h1:null;
    }

    //两个无环
    public static Node getIntersectNotRing(Node head1, Node head2) {
        int h1=getSize(head1);
        int h2=getSize(head2);
        if(h2>h1){
            Node temp=null;
            temp=head1;
            head1=head2;
            head2=temp;
            int tmp=0;
            tmp=h1;
            h1=h2;
            h2=tmp;
        }
        int n=h1-h2;
        while (n>0){
            head1=head1.next;
            n--;
        }
        while (head1!=null&&head2!=null){
            if(head1==head2){
                return head1;
            }
            head1=head1.next;
            head2=head2.next;
        }
        return null;
    }

    //获取链表大小
    public static int getSize(Node head) {
        if(head==null){
            return 0;
        }
        int count=0;
        while (head!=null){
            count++;
            head=head.next;
        }
        return count;
    }
}
    原文作者:不爱编程的设计师
    原文地址: https://blog.csdn.net/qq_37433657/article/details/84190321
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞