LeetCode刷题复盘笔记—剑指 Offer 52. 两个链表的第一个公共节点

今日主要总结一下,剑指 Offer 52. 两个链表的第一个公共节点

题目:剑指 Offer 52. 两个链表的第一个公共节点

Leetcode题目地址

题目描述:
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。
数据范围: n≤1000
要求:空间复杂度 O(1),时间复杂度 O(n)

示例 1:

输入:两个相交链表的两个头结点指针
输出:相交链表交点处结点指针

注意:

如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

一、开始的错误解法

这道题开始我就想着要找两个链表第一个val相同的结点就是相交结点,就让我想到了,LeetCode的第一题,两数之和,把一个链表的val存到hashtable,之后遍历另一个链表val,只要找到一样的val,就return

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_map<int, int> hashtable;
        ListNode *curA = headA;
        ListNode *curB = headB;
        while(curA != NULL){
            hashtable[curA->val] =  1;
            curA = curA->next;
        }
        while(curB != NULL){
            if(hashtable.find(curB->val)!=hashtable.end()){
                return curB;
            }
        }
        return NULL;      
    }
};

本题重难点

简单来说,就是求两个链表交点节点的指针。 这里要注意,交点不是数值相等,而是指针相等!!!

二、正确解法

方法一:集合set法

这个就是我最开始想法的正确解法,应该存入节点指针,而不是存入val
1.遍历链表headA,并存入set中
2.遍历headB,边遍历边在set中查找是否有相同元素

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        set<ListNode *> s;
        while(headA){
            s.insert(headA);
            headA = headA -> next;
            }

        while(headB){
            if(s.find(headB) != s.end()){
                return headB;
            }
            headB = headB -> next;
        }
        return NULL;
    }
};
方法二:让两个链表头指针移至同一起点

先统计两个链表的长度,如果两个链表的长度不一样,就让链表长的先走,直到两个链表长度一样,这个时候两个链表再同时每次往后移一步,看节点是否一样,如果有相等的,说明这个相等的节点就是两链表的交点,否则如果走完了还没有找到相等的节点,说明他们没有交点,直接返回null即可,来画个图看一下。
在这里插入图片描述

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *curA = headA;
        ListNode *curB = headB;
        int lenA = 0,lenB = 0;
        while(curA != NULL){
            ++lenA;
            curA = curA->next;
        }
        while(curB != NULL){
            ++lenB;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        if(lenA < lenB){
            swap(lenA , lenB);
            swap(curA , curB);
        }
        int gap = lenA - lenB;
        while(gap --){
            curA = curA -> next;
        }
        while(curA != NULL){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;      
    }
};

方法三:双指针法

这个双指针还有一个名字叫做浪漫相遇:

你变成我,走过我走过的路
我变成你,走过你走过的路
然后我们便相遇了…

就是我们考虑到两个链表在相交之前长度很可能不同,这个时候同时跑就会一直有差距一直不会相遇,所以我们有了方法一,开始先移至同一起跑线。同样的,双指针是指假设两个链表公共节点之前(包括公共节点)长度分别为m和n,公共节点之后的公共长度为t,使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结点遍历,当 node1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;当 node2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点。这样最后两个在相遇之前,就跑了同样的距离,第一次少跑的重新定位后的第二次就会多跑,相遇时两个指针都跑了(m+n+t),如果没有公共节点就会在一起移至最后一个节点 return NULL

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *curA = headA;
        ListNode *curB = headB;
        while(curA != curB){
            if(curA == NULL)
                curA = headB;
            else 
                curA = curA -> next;
            if(curB == NULL)
                curB = headA;
            else 
                curB = curB -> next;     
        }
        return curA;
    }
};

总结

二、算法思想

寻找链表的公共节点,就是求两个链表交点节点的指针。 这里要注意,交点不是数值相等,而是指针相等!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Al资料站与复盘笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值