当前位置:   article > 正文

算法力扣刷题记录 十一【160.链表相交】

算法力扣刷题记录 十一【160.链表相交】

前言

记录 十一:力扣【160.链表相交】
加油,继续;


一、题目阅读

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交:
在这里插入图片描述

题目数据 保证 整个链式结构中不存在环

注意,函数返回结果后,链表必须 保持其原始结构

自定义评测

评测系统 的输入如下(你设计的程序 不适用 此输入):

intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
listA - 第一个链表
listB - 第二个链表
skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

示例 1
在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

注意:
(1)相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置。
(2)而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

示例 2
在这里插入图片描述

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
  • 1
  • 2
  • 3
  • 4
  • 5

示例 3
在这里插入图片描述

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
  • 1
  • 2
  • 3
  • 4
  • 5

提示:

listA 中节点数目为 m
listB 中节点数目为 n
1 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA] == listB[skipB]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

进阶:

你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?
  • 1

二、第一次尝试

先不考虑进阶,实现过程。

初始思路:

暴力解法:

  • curA = headA,curB = headB,大循环是遍历headA。在内部,遍历链表B。
  • 看存不存在curB->next == curA.

代码初次实现(测试不通过):

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;

        while(curA != nullptr){
             curB = headB;
            while(curB != nullptr){
                if(curB->next == curA)
                {
                    return curA;
                }
                curB = curB->next;
            }
            curA=curA->next;
        }
        return curA;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

检查:发现if(curB->next == curA)忽略了headB是链表相交的节点。所以需要把headB包含上,实现方法:加虚拟头节点指向headB。

代码进一步补充**(测试通过)**:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* dummy_node = new ListNode(0,headB);
        ListNode* curA = headA;
        ListNode* curB = dummy_node;

        while(curA != nullptr){
             curB = dummy_node;
            while(curB != nullptr){
                if(curB->next == curA)
                {
                    return curA;
                }
                curB = curB->next;
            }
            curA=curA->next;

        }

        delete dummy_node;
        return curA;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

很明显时间复杂度很高,外层循环最差执行链表A的长度m,内层循环最差执行m*n次。

进阶

时间复杂度O(m+n),如何实现?

前提:不让修改链表结构。

没有想到办法。学习参考。


三、代码随想录

学习内容

  • 第一步:求出链表A和链表B的长度。比较两者之差。
  • 假设curA指向链表更长的,curB指向较短的那个链表。
  • 第二步:让两个链表的末尾对齐,curA剩余元素和curB剩余元素一样。
  • 第三步:同时后移curA和curB,判断指针位置是否相同。

思路:链表后面相交,让两个尾部对齐。较长的链表前面超出的部分肯定不存在交点,所以从较短链表的长度往后找。

代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0;
        int lenB = 0;

        while(curA != nullptr){
            curA=curA->next;
            lenA++;
        }
        while(curB != nullptr){
            curB=curB->next;
            lenB++;
        }
        curA= headA;
        curB = headB;
        //假设curA指向长链表,lenA是长链表的数。
        if(lenB> lenA){
            swap(curA,curB);
            swap(lenA,lenB);
        }

        int gap = lenA - lenB;

        //对齐
        while(gap--){
            curA = curA->next;
        }

        while(curA != nullptr &&curB!= nullptr){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }



        return curA;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

总结

找链表的交点,肯定在对齐后重合的地方,不是在长链表前面多出的节点。

(欢迎指正,转载标明出处)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/806256
推荐阅读
相关标签
  

闽ICP备14008679号