跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

链表经典算法题解:相加、重排与合并

链表算法实战涵盖两数相加、节点两两交换、链表重排、K 个升序链表合并及 K 组翻转五大场景。通过模拟指针操作、优先队列建堆、分治递归等策略,详解内存管理与逻辑细节,提供可直接参考的 C++ 实现方案。

奇形怪状发布于 2026/3/30更新于 2026/10/778 浏览

链表核心算法实战

链表操作是数据结构面试中的高频考点,涉及指针变换、内存管理及递归思维。以下整理五道经典题目,涵盖模拟、堆结构、分治等策略,代码均基于 C++ 实现。

1. 两数相加

两个链表逆序存储数字,个位对齐。直接遍历相加即可,关键在于处理进位。若最高位仍有进位,需新增节点。

/**
 * Definition for singly-linked list.
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* cur1 = l1, *cur2 = l2;
        ListNode* dummyHead = new ListNode(0);
        ListNode* tail = dummyHead;
        int carry = 0;

        while (cur1 || cur2 || carry) {
            if (cur1) {
                carry += cur1->val;
                cur1 = cur1->next;
            }
            if (cur2) {
                carry += cur2->val;
                cur2 = cur2->next;
            }
            ListNode* node = new ListNode(carry % 10);
            tail->next = node;
            tail = tail->next;
            carry /= 10;
        }

        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

2. 两两交换链表中的节点

通过调整指针指向完成节点交换。使用虚拟头结点简化边界处理,注意保存 next 指针防止断链。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (!head || !head->next) return head;
        
        ListNode* dummyHead = new ListNode(0, head);
        ListNode* prev = dummyHead;
        ListNode* cur = head;

        while (cur && cur->next) {
            ListNode* nextNode = cur->next;
            ListNode* nNext = nextNode->next;

            // 交换
            prev->next = nextNode;
            cur->next = nNext;
            nextNode->next = cur;

            // 移动指针
            prev = cur;
            cur = nNext;
        }

        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

3. 重排链表

将链表分为两半,反转后半部分,然后交替合并。核心在于找到中间节点及头插法反转。

class Solution {
public:
    void reorderList(ListNode* head) {
        if (!head || !head->next || !head->next->next) return;

        // 1. 找中间节点
        ListNode* slow = head, *fast = head;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }

        // 2. 断开并反转后半部分
        ListNode* head2 = new ListNode(0);
        ListNode* cur = slow->next;
        slow->next = nullptr;

        while (cur) {
            ListNode* next = cur->next;
            cur->next = head2->next;
            head2->next = cur;
            cur = next;
        }

        // 3. 合并两条链表
        ListNode* ret = new ListNode(0);
        ListNode* prev = ret;
        ListNode* p1 = head, *p2 = head2->next;

        while (p1) {
            prev->next = p1;
            prev = prev->next;
            p1 = p1->next;
            if (p2) {
                prev->next = p2;
                p2 = p2->next;
                prev = prev->next;
            }
        }

        delete head2;
        delete ret;
    }
};

4. 合并 K 个升序链表

方法一:优先队列(堆)

维护一个最小堆,每次取出当前所有链表头节点中最小的元素加入结果链表,并将该节点的下一个节点入堆。

class Solution {
public:
    struct cmp {
        bool operator()(ListNode* l1, ListNode* l2) {
            return l1->val > l2->val;
        }
    };

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, cmp> heap;
        for (auto l : lists) {
            if (l) heap.push(l);
        }

        ListNode* dummyHead = new ListNode(0);
        ListNode* prev = dummyHead;

        while (!heap.empty()) {
            ListNode* t = heap.top();
            heap.pop();
            prev->next = t;
            prev = prev->next;

            if (t->next) {
                heap.push(t->next);
            }
        }

        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

方法二:分治递归

利用二分思想,将链表列表两两合并,减少比较次数。时间复杂度 O(N log K)。

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.empty()) return nullptr;
        return merge(lists, 0, lists.size() - 1);
    }

private:
    ListNode* merge(vector<ListNode*>& lists, int left, int right) {
        if (left == right) return lists[left];
        int mid = (left + right) >> 1;
        ListNode* l1 = merge(lists, left, mid);
        ListNode* l2 = merge(lists, mid + 1, right);
        return mergeTwoSortedLists(l1, l2);
    }

    ListNode* mergeTwoSortedLists(ListNode* l1, ListNode* l2) {
        if (!l1) return l2;
        if (!l2) return l1;

        ListNode head;
        ListNode* prev = &head;

        while (l1 && l2) {
            if (l1->val <= l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
        prev->next = l1 ? l1 : l2;
        return head.next;
    }
};

5. K 个一组翻转链表

按 k 个节点为一组进行分组,组内反转后连接。需先计算总长度确定完整组数,剩余不足 k 的节点保持原样。

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        int n = 0;
        ListNode* cur = head;
        while (cur) {
            n++;
            cur = cur->next;
        }

        int groups = n / k;
        ListNode* dummyHead = new ListNode(0);
        ListNode* prev = dummyHead;
        cur = head;

        while (groups--) {
            ListNode* groupStart = cur;
            for (int i = 0; i < k; ++i) {
                ListNode* next = cur->next;
                cur->next = prev->next;
                prev->next = cur;
                cur = next;
            }
            prev = groupStart;
        }

        prev->next = cur;
        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

目录

  1. 链表核心算法实战
  2. 1. 两数相加
  3. 2. 两两交换链表中的节点
  4. 3. 重排链表
  5. 4. 合并 K 个升序链表
  6. 方法一:优先队列(堆)
  7. 方法二:分治递归
  8. 5. K 个一组翻转链表

更多推荐文章

查看全部
  • 主流 Python IDE 优缺点对比与选型指南
  • 基于 Verilog 的数字密码锁设计与 FPGA 实现
  • CS144 课程 C++ 核心知识点总结
  • AI 调参技巧:贝叶斯优化 Optuna
  • Trae 结合 Vizro:低代码构建数据可视化仪表板
  • Agent Skills 完全教程:AI 智能体技能开发指南
  • Stable Diffusion 3.5 硬件准备与环境配置:低显存优化方案
  • AI 大模型 40 年发展历程与未来统一趋势研究
  • 2026 年 3 月全球大模型全景:国产登顶、百万上下文与智能体爆发
  • OpenClaw 钉钉群聊多机器人配置指南
  • OpenClaw 深度解析:AI 代理的潜力、风险与真实定位
  • LLM 逻辑推演策略:推理时与训练时计算选择
  • 前端地图 SDK 集成实战:高德/百度/腾讯/Google Maps 接入与封装
  • Docker 可视化管理与远程访问配置指南
  • Python 程序员如何快速入门 Go:Go 与 Python 全面对比
  • 基于冠豪猪优化算法的无人机三维路径规划与 Matlab 实现
  • 利用 AI 大模型辅助少儿编程学习与实践
  • ToDesk 推出 ToClaw:AI 助手可执行电脑操作
  • Kotti Next 调试记录:后端连通与前端轻量级重构方案
  • Linux Shell 脚本基础与实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online