LeetCode 160.相交链表

273 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目:给定两个链表的头节点,判断两个链表是否相交,如果相交则返回相交的起始节点,否则返回null。

解题思路

本题和环形链表的思路类似,简单的思路是将headAheadB链表的节点一个个入HashSet,每次入集合都判断该节点是否已经在Set中,如果存在则直接返回当前节点,如果两个链表都遍历完了则返回null,可得如下代码:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        HashSet<ListNode> set = new HashSet<>();
        while(headA!=null&&headB!=null){
            if(set.contains(headA)){
                return headA;
            }else {
                set.add(headA);
            }
            headA = headA.next;
            if(set.contains(headB)){
                return headB;
            }else {
                set.add(headB);
            }
            headB = headB.next;
        }
        while(headA!=null){
            if(set.contains(headA)){
                return headA;
            }
            set.add(headA);
            headA = headA.next;
        }

        while(headB!=null){
            if(set.contains(headB)){
                return headB;
            }
            set.add(headB);
            headB = headB.next;
        }
        return null;
    }

代码的时间复杂度为O(n)O(n),空间复杂度为O(n)O(n)。题目要求空间复杂度为O(1)O(1),那么可以换一种思路,不使用额外的空间。

此时只需要保证两个链表保持相同的长度向后走,之后每走一步都判断一下两个节点是否相同,如果相同则是相交点,如果最终都走向了null则代表两个链表不相交,此时返回null即可。具体流程是:

首先分别计算俩个链表的长度,之后判断哪个链表长并且计算两个链表之间的差值,让长的链表走差值的距离之后,两个链表再同时走即可,可得代码如下:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0;
        int lenB = 0;
        ListNode curA = headA;
        ListNode curB = headB;
        while(curA!=null){
            curA = curA.next;
            lenA++;
        }
        while(curB!=null){
            curB = curB.next;
            lenB++;
        }
        int preStep = lenA-lenB;
        if(preStep>0){
            while(preStep>0){
                headA = headA.next;
                preStep--;
            }
        }
        else if(preStep<0){
            while (-preStep>0){
                headB = headB.next;
                preStep++;
            }
        }
        while(headA!=null&&headB!=null){
            if(headA==headB){
                return headA;
            }
            headA = headA.next;
            headB = headB.next;
        }
        return null;
    }

上述代码的时间复杂度为O(n)O(n),空间复杂度为O(1)O(1)

还有一种方式不需要计算两个链表的长度,可以通过移动消除两个链表长度不一致的影响,思路如下:

设定两个指针preApreB分别指向headAheadB,让preApreB同时移动,当一个指针到null时,另一个指针剩下的路程即为两条链表的长度差,此时将已经走完的指针指向另一条指针,而等未走完的指针走完指向另一条链表,此时两个指针指向的链表的长度就能保持一致,之后往后走边走边判断即可,代码如下:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null||headB==null) return null;
        ListNode pA = headA, pB = headB;
        while(pA!=pB){
            pA = pA==null?headB:pA.next;
            pB = pB== null?headA:pB.next;
        }
        return pA;
    }

时间复杂度O(n)O(n),空间复杂度也是O(1)O(1)