【LeetCode_160】相交链表

刷爆LeetCode系列

LeetCode第160题:

github地址

有梦想的电信狗

前言

本文用C++实现LeetCode第160题


题目描述

题目链接https://leetcode.cn/problems/intersection-of-two-linked-lists/description/



题目与思路分析

目标分析

  1. 给定两个单链表的头节点 headAheadB ,找出并返回两个单链表相交的起始节点

  2. 如果两个链表不存在相交节点,返回 nullptr

  3. 提高要求 :时间复杂度为O(m + n),空间复杂度为O(1),其中mn分别为两个链表的长度

思路一:暴力解法

思路 :两层循环:遍历链表A和链表B,将链表A中的每个结点的地址都和链表B中的每个结点的地址进行比较,如果地址相等,则相交。

操作

  • ListNode* curNode1 = headA, *curNode2 = headBcurNode1curNode2分别用于迭代遍历两个链表

  • 链表A中的每个节点 需要和链表B中的每个结点进行比较

    cpp 复制代码
      while(curNode1){
          while(curNode2){
              if(curNode1 == curNode2)
                  return curNode1;
              else
                  curNode2 = curNode2->next;
          }
          curNode1 = curNode1->next;
          curNode2 = headB;
      }
    • curNode1 == curNode2时:代表是相交的结点,返回当前结点即可

    • else:内层循环中,curNode2移向下一个节点

  • 内层循环结束一轮后

    • 链表A的curNode1向后移动:curNode1 = curNode1->next
    • 链表B的迭代结点回到链表B的头结点,准备进行下一轮遍历:curNode2 = headB;
  • 循环内没有return时,代表没有相交。循环结束后return nullptr;

  • 时间复杂度O(n^2),空间复杂度O(1)

思路二:快慢指针

思路快慢指针解法

  1. 先分别求两个链表的长度
  2. 长的链表的curNode指针先向后移动两个链表长度的差距步
  3. 两个迭代指针再同时移动,第一个地址相同的结点就是交点

操作

  • ListNode* curNode1 = headA, *curNode2 = headBcurNode1curNode2分别用于迭代遍历两个链表

  • 求链表长度的子函数

    cpp 复制代码
      private:
          size_t getLength(ListNode* list){
              ListNode* curNode = list;
              size_t length = 0;
              while(curNode){
                  ++length;
                  curNode = curNode->next;
              }
              return length;
          }
  • 分别求两个链表的长度

    • size_t lengthA = getLength(headA)size_t lengthB = getLength(headB);
  • 比较两个链表的长度 ,长的链表的curNode指针先移动差距步

  • 再让两个curNode指针同时移动,第一个相同的地址就是交点

  • 时间复杂度O(m + n),空间复杂度O(1)

代码实现

思路一:暴力解法

  • 暴力解法 :时间复杂度O(n^2),空间复杂度O(1)
cpp 复制代码
// 暴力解法 O(n^2)
class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* curNode1 = headA, *curNode2 = headB;
        while(curNode1){
            while(curNode2){
                if(curNode1 == curNode2)
                    return curNode1;
                else
                    curNode2 = curNode2->next;
            }
            curNode1 = curNode1->next;
            curNode2 = headB;
        }
        return nullptr;
    }
};

思路二:快慢指针

  • 快慢指针解法 :时间复杂度O(m + n),空间复杂度O(1),其中mn分别为两个链表的长度
cpp 复制代码
// 时间复杂度为O(m + n)的解法
class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* curNode1 = headA, *curNode2 = headB;
        // 分别求两个链表的长度
        size_t lengthA = getLength(headA);
        size_t lengthB = getLength(headB);
        // 长的链表先走差距步
        if(lengthA > lengthB){
            size_t gap = lengthA - lengthB;
            while(gap--)
                curNode1 = curNode1->next;
        }
        else{
            size_t gap = lengthB - lengthA;
            while(gap--)
                curNode2 = curNode2->next;
        }
        // 两个链表再同时走,第一个相同的地址就是交点
        while(curNode1){
            if(curNode1 == curNode2)
                return curNode1;
            else{
                curNode1 = curNode1->next;
                curNode2 = curNode2->next;
            }
        }
        return nullptr;
    }
private:
    size_t getLength(ListNode* list){
        ListNode* curNode = list;
        size_t length = 0;
        while(curNode){
            ++length;
            curNode = curNode->next;
        }
        return length;
    }
};

算法代码优化

  • 思路二代码优化 :优化比较链表长度的逻辑,减少逻辑重复的代码
cpp 复制代码
// 优化找长链表的逻辑  时间复杂度为O(m + n)的解法
class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode* curNode1 = headA, *curNode2 = headB;
        // 分别求两个链表的长度
        size_t lengthA = getLength(headA);
        size_t lengthB = getLength(headB);
        // 长的链表先走差距步
        // 优化找长的链表的逻辑 ,假设A比B长,再加一个修正假设的逻辑
        ListNode* longList = headA, *shortList = headB;
        size_t gap = lengthA - lengthB;
        if(lengthA < lengthB){
            longList = headB;
            shortList = headA;
            gap = lengthB - lengthA;
        }
        // 长链表先走差距步
        while(gap--)
            longList = longList->next;
       
        // 两个链表再同时走,第一个相同的地址就是交点
        while(longList){
            if(longList == shortList)
                return longList;
            else{
                longList = longList->next;
                shortList = shortList->next;
            }
        }
        return nullptr;
    }
private:
    size_t getLength(ListNode* list){
        ListNode* curNode = list;
        size_t length = 0;
        while(curNode){
            ++length;
            curNode = curNode->next;
        }
        return length;
    }
};

以上就是本文的所有内容了,如果觉得文章对你有帮助,欢迎 点赞⭐收藏 支持!如有疑问或建议,请在评论区留言交流,我们一起进步

分享到此结束啦
一键三连,好运连连!

你的每一次互动,都是对作者最大的鼓励!


征程尚未结束,让我们在广阔的世界里继续前行! 🚀

相关推荐
IronMurphy4 小时前
【算法四十三】279. 完全平方数
算法
墨染天姬4 小时前
【AI】Hermes的GEPA算法
人工智能·算法
mount_myj4 小时前
长长久久【C语言】
c语言
papership4 小时前
【入门级-数据结构-3、特殊树:完全二叉树的数组表示法】
数据结构·算法·链表
smj2302_796826524 小时前
解决leetcode第3911题.移除子数组元素后第k小偶数
数据结构·python·算法·leetcode
山甫aa5 小时前
差分数组 ----- 从零开始的数据结构
数据结构
早日退休!!!5 小时前
《数据结构选型指南》笔记
数据结构·数据库·oracle
九转成圣5 小时前
Java 性能优化实战:如何将海量扁平数据高效转化为类目字典树?
java·开发语言·json
Beginner x_u5 小时前
链表专题:JS 实现原理与高频算法题总结
javascript·算法·链表
SmartRadio5 小时前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi