一文搞懂链表相关算法

目录

链表的逆序和截断

逆序

截断

查找链表的中间节点

力扣题


博主主页:东洛的克莱斯韦克-CSDN博客

链表的逆序和截断

逆序

推荐使用头插法逆序,首先要 new 一个虚拟头节点------newNode。如下图

链表的头节点为head,由cur指针指向head,逆序算法如下:

  1. next = cur->next;

2.cur->next = newNode->next;

3.newNode->next = cur;

4.cur = next;

为了防止cur找不到下一个节点,要提前用next保存起来,cur遍历到的节点都会放到newNode的后面,当cur遍历完整个链表后,newNode后面就是逆序后的链表。

该算法的结束条件是:

cur == nullptr;

时间复杂度为 , 空间复杂度为

截断

在上述算法的基础上我们给newNode一个指针newNode_cur ,如下图

把head链表上的节点插入到newNode_cur后newNode_cur指针向后移动一格。

1.next = cur->next;

2.cur->next = newNode_cur->next;

3.newNode_cur->next = cur;

4.cur = next;

5.newNode_cur = newNode_cur->next;

为了防止cur找不到下一个节点,依旧让next记录cur的下一个节点的位置。这次newNode后面是顺序的链表。

结束条件取决于要截断多少节点,如果结束条件是

cur == nullptr

那么上述截断算法等价于下述代码

newNode->next = head;

相当于把head链表连入newNode链表的后面。

查找链表的中间节点

用快慢双指针算法。慢指针 slow 每次移动一个节点,快指针 fast 每次移动两个节点,slow 和 fast 都初始化(指向)为链表的头节点, 算法如下

while (fast && fast->next) {

slow = slow->next;

fast = fast->next->next;

}

结果如下图示意

  1. 当 fast 为空时,链表为偶数,slow指针会落在中间靠右的节点上

  2. 当 fast->next 为空时,链表为基数,slow指针会落在中间的节点上

力扣题

LCR 026. 重排链表 - 力扣(LeetCode)

这道题比较综合,大题思路就是先找中间节点,再把后半部分链表逆序,然后把逆序后的链表重排到前半部分的链表中。

cpp 复制代码
class Solution {
public:
    void reorderList(ListNode* head) {
        //边界情况
        if (head == nullptr || head->next == nullptr || head->next->next == nullptr) return;
        //找中间节点
        ListNode* left = head, *right = head;
        while (right && right->next) {
            left = left->next;
            right = right->next->next;
        }
        //把 left 后面的节点逆序
        ListNode* head1 = new ListNode();
        ListNode* cur = left->next; left->next = nullptr;
        while (cur) {
            ListNode* next = cur->next;
            cur->next = head1->next;
            head1->next = cur;
            cur = next;
        }
        //链表重排
        ListNode* ret = new ListNode();
        cur = ret;
        ListNode* head2 = head1->next;
        while (head) {
            ListNode* next = head->next;
            head->next = cur->next;
            cur->next = head;
            head = next;
            cur = cur->next;
            if (head2) {
                ListNode* next1 = head2->next;
                head2->next = cur->next;
                cur->next = head2;
                head2 = next1;
                cur = cur->next;
            }
        }
        //更新结果,释放虚拟节点
        head = ret->next;
        delete ret;
        delete head1;
    }
};

LCR 078. 合并 K 个升序链表 - 力扣(LeetCode)

如果用暴力解法的话时间复杂度会非常高,可以考虑用优先级队列做优化

cpp 复制代码
class Solution {

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

public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        //小跟堆
        priority_queue<ListNode*, vector<ListNode*>, cmp> heap;
        ListNode* ret = new ListNode();
        ListNode* cur = ret;

        //把链表的头结点放入优先级队列
        for(auto l : lists) { if (l) heap.push(l); }

        while (!(heap.empty())) {
            ListNode* t = heap.top();
            ListNode* next = t->next;   //记录链表的下一个节点
            t->next = cur->next;        //插入到ret的后面
            cur->next = t;              //插入到ret的后面
            cur = cur->next;
            heap.pop();
            if(next) heap.push(next);
        }

        cur = ret->next;
        delete ret;
        return cur;
    }
};

其他一些链表题

25. K 个一组翻转链表 - 力扣(LeetCode)

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

141. 环形链表 - 力扣(LeetCode)

138. 随机链表的复制 - 力扣(LeetCode)

138这道题很考验对链表的把控

LCR 077. 排序链表 - 力扣(LeetCode)

相关推荐
智者知已应修善业1 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn1 小时前
Java Set集合相关知识点
java·开发语言·算法
生成论实验室2 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构
AI科技星2 小时前
全域数学·72分册:场计算机卷【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
科研前沿3 小时前
镜像孪生VS视频孪生核心技术产品核心优势
大数据·人工智能·算法·重构·空间计算
水蓝烟雨3 小时前
1931. 用三种不同颜色为网格涂色
算法·leetcode
晨曦夜月4 小时前
map与unordered_map区别
算法·哈希算法
qeen874 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码4 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler014 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法