当前位置: 首页 > article >正文

每日一题--相交链表

离思五首-元稹

曾经沧海难为水,除却巫山不是云。
取次花丛懒回顾,半缘修道半缘君。

目录

题目描述:

思路分析:

方法及时间复杂度:

法一 计算链表长度(暴力解法)

法二 栈

法三 哈希集合

法四 map或unordered_map

法五 双指针(经典解法)

法六 递归(烧脑解法)

个人总结


题目描述:

相交返回相交结点,不相交返回

160. 相交链表 - 力扣(LeetCode)

思路分析:

要找相交的那个结点,可以让两个起始位置相同的指针遍历两个链表,当指针所指结点位置相同时,就是相交结点。简单粗暴。

 也可以用哈希,栈等方法,详情如下。

方法及时间复杂度:

法一 计算链表长度(暴力解法)

计算两个链表长度m,n。再定义两个指针,要使两个指针在同一起始位置,需要使长链表的那个指针那个先走abs(m-n)步

 双指针同时走,相同则为相交。否则同时走到空。代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA=0,lenB=0;
        ListNode* cur=headA;
        while(cur){
            ++lenA;
            cur=cur->next;
        }
        cur=headB;
        while(cur){
            ++lenB;
            cur=cur->next;
        }
        int gap=abs(lenA-lenB);//两链表的差距
        ListNode* fast=nullptr,*slow=nullptr;
        if(lenA>lenB){
            fast=headA;
            slow=headB;
        }else{
            fast=headB;
            slow=headA;
        }
        while(gap--){
            fast=fast->next;//fast先走gap步
        }
        while(fast){
            if(fast==slow){
                return fast;
            }
            fast=fast->next;
            slow=slow->next;
        }
        return nullptr;
    }
};

时间复杂度O(m+n),m,n为两个链表长度

空间复杂度O(1)

法二 栈

设两个栈,将两个链表的结点分别入栈,依次访问栈顶元素,如果相交,则栈顶元素相等的最后一个结点为相交结点。不相交说明栈顶元素不相同,直接返回空。

 代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        stack<ListNode*> stA,stB;
        ListNode* cur=headA;
        while(cur){
            stA.emplace(cur);
            cur=cur->next;
        }
        cur=headB;
        while(cur){
            stB.emplace(cur);
            cur=cur->next;
        }
        while(!stA.empty()&&!stB.empty()&&stA.top()==stB.top()){
            cur=stA.top();
            stA.pop();
            stB.pop();
        }
        return cur;
    }
};

时间复杂度O(m+n)

空间复杂度O(m+n)

法三 哈希集合

将第一个链表放入集合中,在遍历第二个链表的结点,然后在集合中查找,如果查找到的第一个结点,就是相交结点,直接返回,否则返回空。代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set<ListNode*> hash;
        ListNode* cur=headA;
        while(cur){
            hash.insert(cur);
            cur=cur->next;
        }
        cur=headB;
        while(cur){
            if(hash.find(cur)!=hash.end()){
                return cur;
            }
            cur=cur->next;
        }
        return nullptr;
    }
};

时间复杂度O(m+n)

空间复杂度O(m)

法四 map或unordered_map

与法三思路相同,都用的是这几个容器的查找功能,不多解释。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_map<ListNode*, int> hash;
        ListNode* cur = headA;
        while (cur) {
            hash[cur]++;
            cur = cur->next;
        }    
        cur = headB;
        while (cur) {
            if (hash.find(cur) != hash.end()) {
                return cur;
            }
            cur = cur->next;
        }
        return nullptr;
    }
};

时间复杂度O(m+n)

空间复杂度O(m)

 map还可以这样:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        map<ListNode*,int> nodes;
        ListNode* cur=headA;
        while(cur){
            nodes[cur]++;
            cur=cur->next;
        }
        cur=headB;
        while(cur){
            nodes[cur]++;
            cur=cur->next;
        }
        for(auto node:nodes){
            if(node.second==2){
                return node.first;
            }
        }
        return nullptr;
    }
};

时间复杂度O(m+n)

空间复杂度O(m+n)

法五 双指针(经典解法)

 "来时路上不见你,于是便走你来时的路,相遇时才发现你也走过我曾走过的路💓"

class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
      ListNode *Girl = headA, *Boy = headB;
      while (Girl!=Boy) {
          Girl=Girl==nullptr ? headB:Girl->next;
          Boy = Boy==nullptr ? headA:Boy->next;
      }
     return Boy;
   }
};

时间复杂度O(m+n)

空间复杂度O(1)

利用抽象思维和数学思维,可以将两条链表连接成一条带环链表,让两个指针同时走,环的入口就是相交结点,相逢何必曾相识,同是天涯沦落人,相交就一定会相逢,不相交都走向空。

原理:两指针相遇时,走的距离是相同的。设两条链表未相交部分长度为a,b。相交部分的长度为c。则有a+c+b==b+c+a。当一指针走向空时,则走到另一个链表的开始。

 

法六 递归(烧脑解法)

首先定义一个递归函数`dfs`,该函数接收3个指针参数:指向链表A当前节点的指针`curA`,指向链表B当前节点的指针`curB`,以及链表B的头节点指针`headB`。 

如果A链表和B链表相交,即相交节点之后的节点全部相同,则直接返回相交节点  `(curA==curB)`,表示两个指针指向的节点相同,那么这个节点就是相交节点,直接返回即可。

如果两个指针都没有遍历到链表的结尾,则继续往下遍历,即更新指向链表B节点的指针,直到有一个链表遍历结束,进入下一步操作。

如果B链表已经到达了链表末尾,那么就把`curB`指针指向 `headB`,即链表B的头节点,同时把`curA`指针指向下一个节点,继续查找。这样做的本质是相当于把链表B的指针接到了链表A上,形成了一条新的链表,重新遍历该新链表是否存在相交节点。

如果A链表已经到达了链表末尾,那么就把`curA`指针指向`headB`,即链表B的头节点,同时把`curB`指针指向下一个节点,继续查找。这样做的本质也是相当于把链表A的指针接到了链表B上,形成了一条新的链表,重新遍历该新链表是否存在相交节点。

如果上面的步骤都没有找到相交节点,则表明两个链表不相交,返回空指针即可。

最后,在`getIntersectionNode`函数中,调用`dfs`递归函数,传入链表A的头节点`headA`,链表B的头节点`headB`,以及链表B的头节点指针`headBref`,作为参数。函数返回的即为两个链表的相交节点。代码如下:

struct ListNode *dfs(struct ListNode *curA, struct ListNode *curB,struct ListNode *headB){
    if(curA==curB){
        return curB;
    }

    if(curA!=NULL&&curB!=NULL){
        return dfs(curA,curB->next,headB);
    }
    else if(curB==NULL&&curA!=NULL){
        return dfs(curA->next,headB,headB);
    }else{
        return NULL;
    }
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    return dfs(headA,headB,headB);
}

时间复杂度O(m+n)

空间复杂度O(max(m,n))

用c++超时,用c语言不会。毕竟c语言是世界上最好的语言。

个人总结

俗话说,温故而知新。第一次看这道题时,没有想到那么多解法。随着知识面的扩张,对旧的东西又有了新的感悟。


http://www.kler.cn/a/145771.html

相关文章:

  • 使用vue-next-admin框架后台修改动态路由
  • 快手SDK接入错误处理经验总结(WebGL方案)
  • Hadoop•搭建完全分布式集群
  • 2025年PHP面试宝典,技术总结。
  • 玉米植物结构受乙烯生物合成基因 ZmACS7 的调控
  • python学opencv|读取图像(三十九 )阈值处理Otsu方法
  • 【云原生】什么是 Kubernetes ?
  • 2023年初中生古诗文大会复选最后6天备考策略和更新的在线模拟题
  • 思福迪 运维安全管理系统 test_qrcode_b 远程命令执行漏洞
  • 【深度学习】DAMO-YOLO,阿里,701类通用检测模型,目标检测
  • Co-DETR:DETRs与协同混合分配训练代码学习笔记
  • 汇编-CALL和RET指令
  • C++初识类和对象
  • 【python】Python将100个PDF文件对应的json文件存储到MySql数据库(源码)【独一无二】
  • Navicat 技术指引 | GaussDB服务器对象的创建/设计(编辑)
  • 【咕咕送书 | 第六期】深入浅出阐述嵌入式虚拟机原理,实现“小而能”嵌入式虚拟机!
  • 大模型能否生成搜索引擎的未来?
  • C++中constexpr的作用
  • 开源WIFI继电器之源代码
  • video标签在h5中被劫持问题
  • 开源vs闭源,处在大模型洪流中,向何处去?
  • YOLOv5结合华为诺亚VanillaNet Block模块
  • git 文件被莫名其妙的或略且无论如何都查不到哪个.gitignore文件忽略的
  • 【iOS】数据持久化(二)之归档和解档(iOS 13以后)
  • TypeScript 中的type与interface
  • 【Layui】动态时间线