【LeetCode_160】相交链表

【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中的每个结点进行比较
    • curNode1 == curNode2时:代表是相交的结点,返回当前结点即可
    • else:内层循环中,curNode2移向下一个节点
  • 内层循环结束一轮后
    • 链表A的curNode1向后移动:curNode1 = curNode1->next
    • 链表B的迭代结点回到链表B的头结点,准备进行下一轮遍历:curNode2 = headB;
  • 循环内没有return时,代表没有相交。循环结束后return nullptr;
  • 时间复杂度O(n^2),空间复杂度O(1)
while(curNode1){while(curNode2){if(curNode1 == curNode2)return curNode1;else curNode2 = curNode2->next;} curNode1 = curNode1->next; curNode2 = headB;}

思路二:快慢指针

思路快慢指针解法

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

操作

  • ListNode* curNode1 = headA, *curNode2 = headBcurNode1curNode2分别用于迭代遍历两个链表
  • 求链表长度的子函数
  • 分别求两个链表的长度
    • size_t lengthA = getLength(headA)size_t lengthB = getLength(headB);
  • 比较两个链表的长度,长的链表的curNode指针先移动差距步
  • 再让两个curNode指针同时移动,第一个相同的地址就是交点
  • 时间复杂度O(m + n),空间复杂度O(1)
private: size_t getLength(ListNode* list){ ListNode* curNode = list; size_t length =0;while(curNode){++length; curNode = curNode->next;}return length;}
在这里插入图片描述

代码实现

思路一:暴力解法

  • 暴力解法:时间复杂度O(n^2),空间复杂度O(1)
// 暴力解法 O(n^2)classSolution{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;}returnnullptr;}};

思路二:快慢指针

  • 快慢指针解法:时间复杂度O(m + n),空间复杂度O(1),其中mn分别为两个链表的长度
// 时间复杂度为O(m + n)的解法classSolution{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;}}returnnullptr;}private: size_t getLength(ListNode* list){ ListNode* curNode = list; size_t length =0;while(curNode){++length; curNode = curNode->next;}return length;}};

算法代码优化

  • 思路二代码优化:优化比较链表长度的逻辑,减少逻辑重复的代码
// 优化找长链表的逻辑 时间复杂度为O(m + n)的解法classSolution{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;}}returnnullptr;}private: size_t getLength(ListNode* list){ ListNode* curNode = list; size_t length =0;while(curNode){++length; curNode = curNode->next;}return length;}};

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

分享到此结束啦
一键三连,好运连连!
你的每一次互动,都是对作者最大的鼓励!征程尚未结束,让我们在广阔的世界里继续前行! 🚀

Read more

Python快速入门指南:从零开始掌握Python编程

Python快速入门指南:从零开始掌握Python编程

文章目录 * 前言 * 一、Python环境搭建🥏 * 1.1 安装Python * 1.2 验证安装 * 1.3 选择开发工具 * 二、Python基础语法📖 * 2.1 第一个Python程序 * 2.2 变量与数据类型 * 2.3 基本运算 * 三、Python流程控制🌈 * 3.1 条件语句 * 3.2 循环结构 * 四、Python数据结构🎋 * 4.1 列表(List) * 4.2 字典(Dictionary) * 4.3 元组(Tuple)和集合(Set) * 五、函数与模块✨

By Ne0inhk
Python异步编程基石:深入理解asyncio核心原理与实战

Python异步编程基石:深入理解asyncio核心原理与实战

摘要 本文深入剖析Python异步编程核心库asyncio的工作原理,从事件循环、协程、Future到Task的完整技术栈。通过真实性能对比数据、企业级案例和5个架构流程图,全面解析async/await底层机制。涵盖异步编程最佳实践、性能优化技巧和故障排查方案,帮助开发者掌握高并发程序设计精髓,提升I/O密集型应用性能数倍。 1 异步编程:为什么它是Python高性能的关键 在我13年的Python开发经验中,异步编程是性能优化的分水岭。记得曾经处理一个需要调用10个外部API的任务,同步版本需要20多秒,而改用异步后仅需2秒——这种10倍性能提升让我彻底认识到异步编程的价值。 1.1 同步 vs 异步:直观对比 想象你在餐厅点餐的场景: * 同步:点完第一个菜后站着等厨师做完,再点第二个菜,效率极低 * 异步:点完所有菜后找座位等待,厨师并行制作,服务员送餐时通知你 这就是异步编程的核心优势:避免不必要的等待,充分利用等待时间执行其他任务。 import time import asyncio # 同步版本:顺序执行,总耗时=各任务耗时之和 def

By Ne0inhk
【超详细】Python FastAPI 入门:写给新手的“保姆级”教程

【超详细】Python FastAPI 入门:写给新手的“保姆级”教程

前言  作为一名大学生,最近在做 Python Web 开发时发现了一个“宝藏”框架——FastAPI。 以前学 Django 光配置就头大,学 Flask 又不知道怎么写规范。直到遇到了 FastAPI,我才体会到什么叫“写代码像呼吸一样自然”。 这篇文章不讲复杂的原理,只讲最基础、最实用的操作,带你从 0 到 1 跑通第一个 API 接口! 一、FastAPI 是什么 在 Python 的世界里,做网站后台(Web 开发)主要有三巨头: 1. Django:老大哥,功能全但笨重,像一辆重型卡车。 2. Flask:二哥,轻便灵活但插件多,像一辆自行组装的赛车。 3.

By Ne0inhk