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

链表经典算法题详解教程

链表经典算法题详解教程

目录

  1. 链表基础知识
  2. 删除重复节点
  3. 返回倒数第k个节点
  4. 寻找链表中间节点
  5. 反转链表
  6. 环形链表检测
  7. 回文链表判断
  8. 合并两个有序链表

链表基础知识

ListNode 结构定义

struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};

常用技巧

  • 双指针法:快慢指针、前后指针
  • 哑节点(Dummy Node):简化边界处理
  • 哈希表:用于检测重复或环

1. 删除重复节点

问题描述

删除链表中重复出现的节点,保留每个值只出现一次。

解题思路

使用哈希表记录已经出现过的节点值,遍历链表时跳过重复节点。

代码实现

class Solution {
public:ListNode* removeDuplicateNodes(ListNode* head) {// 边界情况:空链表或单节点if(head == nullptr || head->next == nullptr)return head;unordered_map<int, int> mp;  // 哈希表记录出现过的值ListNode* cur = head;ListNode* next = head->next;mp[cur->val] = 1;  // 标记头节点while(next) {if(mp.find(next->val) == mp.end()) {// 未出现过的值,保留该节点mp[next->val] = 1;cur->next = next;cur = next;next = next->next;} else {// 重复值,跳过该节点next = next->next;}}cur->next = next;  // 处理尾节点return head;}
};

复杂度分析

  • 时间复杂度:O(n),遍历链表一次
  • 空间复杂度:O(n),哈希表存储节点值

2. 返回倒数第k个节点

问题描述

返回链表的倒数第 cnt 个节点。

解题思路

使用快慢双指针

  1. 快指针先走 cnt 步
  2. 快慢指针同时移动,直到快指针到达末尾
  3. 此时慢指针指向倒数第 cnt 个节点

代码实现

class Solution {
public:ListNode* trainingPlan(ListNode* head, int cnt) {ListNode *fast = head;ListNode *slow = head;// 快指针先走 cnt 步while(cnt--) {if(fast == nullptr)return nullptr;fast = fast->next;}// 快慢指针同时移动while(fast) {fast = fast->next;slow = slow->next;}return slow;}
};

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3. 寻找链表中间节点

问题描述

返回链表的中间节点。若有两个中间节点,返回第二个。

解题思路

使用快慢指针

  • 快指针每次走2步
  • 慢指针每次走1步
  • 当快指针到达末尾时,慢指针正好在中间

代码实现

class Solution {
public:ListNode* middleNode(ListNode* head) {ListNode *fast = head;ListNode *slow = head;while(fast && fast->next) {fast = fast->next->next;  // 快指针走2步slow = slow->next;         // 慢指针走1步}return slow;}
};

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

4. 反转链表

问题描述

反转一个单链表。

解题思路

使用三指针法

  • pre:前一个节点
  • cur:当前节点
  • next:下一个节点

通过改变指针方向实现反转。

代码实现

class Solution {
public:ListNode* trainningPlan(ListNode* head) {// 边界情况if(head == nullptr || head->next == nullptr)return head;ListNode* pre = nullptr;ListNode* cur = head;ListNode* next = head->next;while(next) {cur->next = pre;  // 反转指针pre = cur;        // 前移cur = next;next = next->next;}cur->next = pre;  // 处理最后一个节点return cur;  // cur 是新的头节点}
};

图解过程

原链表: 1 -> 2 -> 3 -> 4 -> null
步骤1: null <- 1    2 -> 3 -> 4 -> null
步骤2: null <- 1 <- 2    3 -> 4 -> null
步骤3: null <- 1 <- 2 <- 3    4 -> null
步骤4: null <- 1 <- 2 <- 3 <- 4

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

5. 环形链表检测

问题描述

检测链表中是否有环,并找到环的入口节点。

解题思路

使用Floyd判圈算法(快慢指针)

  1. 快慢指针同时出发,快指针每次走2步,慢指针走1步
  2. 如果有环,两指针必定相遇
  3. 相遇后,将快指针重置到头节点
  4. 两指针以相同速度前进,再次相遇点即为环的入口

代码实现(修正版)

class Solution {
public:ListNode* detectCycle(ListNode *head) {ListNode *fast = head;ListNode *slow = head;// 第一阶段:检测是否有环while(fast && fast->next) {slow = slow->next;fast = fast->next->next;if(slow == fast) {// 第二阶段:找到环的入口fast = head;while(slow != fast) {slow = slow->next;fast = fast->next;}return slow;  // 返回环的入口节点}}return nullptr;  // 无环}
};

原理说明

设链表头到环入口距离为 a,环入口到相遇点距离为 b,相遇点到环入口距离为 c。

  • 慢指针走的距离:a + b
  • 快指针走的距离:a + b + c + b = a + 2b + c
  • 因为快指针速度是慢指针的2倍:2(a + b) = a + 2b + c
  • 化简得:a = c

因此,从头节点和相遇点同时出发,相遇点即为环入口。

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

6. 回文链表判断

问题描述

判断链表是否为回文结构。

解题思路

  1. 使用快慢指针找到链表中点
  2. 反转后半部分链表
  3. 比较前半部分和反转后的后半部分

代码实现

class Solution {
public:bool isPalindrome(ListNode* head) {// 1. 找到中间节点ListNode* fast = head;ListNode* slow = head;while(fast && fast->next) {fast = fast->next->next;slow = slow->next;}// 2. 反转后半部分链表ListNode* pre = nullptr;ListNode* cur = slow;ListNode* next = slow->next;while(next) {cur->next = pre;pre = cur;cur = next;next = next->next;}cur->next = pre;// 3. 比较前后两部分while(cur && head) {if(cur->val == head->val) {cur = cur->next;head = head->next;} else {return false;}}return true;}
};

示例

链表: 1 -> 2 -> 3 -> 2 -> 1
中点: 3
后半部分反转: 1 -> 2 -> 3 <- 2 <- 1
比较: 1==1, 2==2, 结果为 true

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

7. 合并两个有序链表

问题描述

将两个升序链表合并为一个新的升序链表。

方法一:迭代法

解题思路

使用哑节点简化操作,依次比较两个链表的节点值,将较小的节点连接到结果链表。

代码实现
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {// 边界情况if (list1 == nullptr || list2 == nullptr)return list1 == nullptr ? list2 : list1;ListNode dummy(0);           // 哑节点ListNode* list3 = &dummy;    // 游标指针ListNode* res = list3;       // 记录结果链表头while (list1 && list2) {if (list1->val < list2->val) {list3->next = list1;list1 = list1->next;} else {list3->next = list2;list2 = list2->next;}list3 = list3->next;}// 连接剩余节点list3->next = (list2 == nullptr) ? list1 : list2;return res->next;}
};
复杂度分析
  • 时间复杂度:O(m + n)
  • 空间复杂度:O(1)

方法二:递归法

解题思路

递归比较两个链表的头节点,将较小的节点与剩余部分的合并结果连接。

代码实现
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {// 递归终止条件if (list1 == nullptr || list2 == nullptr)return list1 == nullptr ? list2 : list1;if(list1->val < list2->val) {list1->next = mergeTwoLists(list1->next, list2);return list1;} else {list2->next = mergeTwoLists(list1, list2->next);return list2;}}
};
复杂度分析
  • 时间复杂度:O(m + n)
  • 空间复杂度:O(m + n),递归栈空间

总结

链表题目常用技巧

技巧适用场景代表题目
快慢指针寻找中点、检测环、倒数第k个节点中间节点、环形链表
哈希表检测重复、记录访问删除重复节点
双指针反转、合并反转链表、合并链表
哑节点简化边界处理合并链表
递归分解子问题合并链表、反转链表

注意事项

  1. 边界条件:空链表、单节点链表
  2. 指针操作:避免断链、空指针访问
  3. 空间优化:尽量使用 O(1) 空间
  4. 代码规范:变量命名清晰,逻辑简洁

练习建议

  1. 先理解算法原理,画图模拟过程
  2. 手写代码,注意边界条件
  3. 多做类似题目,总结规律
  4. 尝试优化空间复杂度
http://www.dtcms.com/a/457748.html

相关文章:

  • 唐山网站建设汉狮怎么样上海牛人岛企业服务有限公司
  • 微网站开发平台wizi网站建设板块如何分类
  • 【材料学python入门】conda、 jupyter、cpu、GPAW、wsl、ubuntu
  • 完整酒店网站开发威海建设网站
  • 高速采集卡ESD方案介绍及验证
  • 建个公司网站一年多少钱wordpress ios7教程
  • 做网站有2个前提条件 一个是网站godaddy做网站
  • 手机网站和微信网站的区别潍坊企业网站建设
  • Qt 支持的绿色系英文颜色(Green Family)
  • 找代做海报的网站广西建筑模板
  • 网站icp备案费用门户网站创新的方式有
  • 购买商标去哪个网站个人所得税app下载
  • Fedora 38 安装 perl-JSON RPM 包步骤(含依赖问题解决及附安装包)​
  • 大岭山建设网站wordpress cx udy
  • 电阻的分类与应用
  • 网站自建系统股票网站开发
  • 网站优化推广 siteasp.net 大型网站开发
  • C++游戏编程入门(第三版)——Timber!!! 项目(章节 1–5)
  • [Linux系统编程——Lesson4.进程状态]
  • PostIn入门到实战(8) - 如何对接口进行全方位自动化测试,有效确保接口质量
  • 平顶山网站网站建设有赞小程序定制开发
  • 冲床电脑控制器说明书
  • 企业网站优化推广怎么做宁波信息港
  • SortedList
  • 【LeetCode热题100(37/100)】二叉树的最大深度
  • 茂名公司制作网站如何制作网站和软件
  • 网站的种类诺邯郸网站建设
  • 河北建设广州分公司网站黄浦网站设计
  • uniapp 设置主备请求地址切换
  • 深入洞察:华为数字化转型之战略规划