C++ 链表OJ

news2024/10/6 4:08:58

目录

1、2. 两数相加

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

3、143. 重排链表

4、23. 合并 K 个升序链表

5、25. K 个一组翻转链表


解决链表题目常用方法:

1、画图
2、引入虚拟"头”结点

  • 便于处理边界情况
  • 方便我们对链表操作

3、大胆定义变量,减少连接节点时出现错误。

4、快慢双指针

  • 判环
  • 找链表中环的入口
  • 找链表中倒数第 n个结点

1、2. 两数相加

 思路:模拟相加,注意进位问题。

/**
 * 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* newhead=new ListNode(0);
        ListNode* cur1=l1,*cur2=l2;
        ListNode* cur=newhead;
        int c=0;//进位
        while(cur1||cur2||c){
            if(cur1){
                c+=cur1->val;
                cur1=cur1->next;
            }
            if(cur2){
                c+=cur2->val;
                cur2=cur2->next;
            }
            cur->next=new ListNode(c%10);
            cur=cur->next;
            c/=10;
        }
        cur=newhead->next;
        delete newhead;
        return cur;
    }
};

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

 思路:循环、迭代(模拟)。定义一个带有虚拟头结点的链表统计结果,接着定义出包括虚拟头结点在内和它后三个节点方便直接插入新链表。

/**
 * 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* swapPairs(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        ListNode* newHead = new ListNode(0);
        newHead->next = head;
        ListNode *prev = newHead, *cur = prev->next, *next = cur->next,
                 *nnext = next->next;
        while (cur && next) {
            prev->next = next;
            next->next = cur;
            cur->next = nnext;
            prev = cur;
            cur = prev->next;
            if (cur)
                next = cur->next;
            if (next)
                nnext = next->next;
        }
        cur = newHead->next;
        delete newHead;
        return cur;
    }
};
  • 首先创建一个新的头节点newHead,其值为0,并将其指向原链表的头节点head
  • 使用指针prev指向newHead,指针cur指向prev的下一个节点(即原链表的头节点),指针next指向cur的下一个节点,指针nnext指向next的下一个节点。
  • 进入循环,条件是curnext都不为空。在循环中:
    • prevnext指针指向next,实现交换相邻节点。
    • nextnext指针指向cur,完成节点交换。
    • curnext指针指向nnext,恢复链表连接。
    • 更新prevcurcurprev的下一个节点,nextcur的下一个节点,nnextnext的下一个节点。
  • 循环结束后,重新定位cur指向新链表的头部,即newHead的下一个节点。
  • 删除创建的头节点newHead,并返回交换后链表的头节点cur

3、143. 重排链表

 思路:快慢双指针找到中间节点,逆序后半部分,利用双指针合并两个链表。

/**
 * 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:
    void reorderList(ListNode* head) {
        if (head == nullptr || head->next == nullptr ||
            head->next->next == nullptr) {
            return;
        }
        ListNode *slow = head, *fast = head;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* rhead = new ListNode(0);
        ListNode* cur = slow->next;//逆序不要中间节点
        slow->next = nullptr;//分离逆序部分
        while (cur) {
            ListNode* next = cur->next;
            cur->next = rhead->next;
            rhead->next = cur;
            cur = next;
        }
        ListNode *cur1 = head, *cur2 = rhead->next;
        ListNode* ret = new ListNode(0);
        ListNode* prev = ret;
        while (cur1) {
            prev->next = cur1;
            cur1 = cur1->next;
            prev = prev->next;
            if (cur2) {
                prev->next = cur2;
                cur2 = cur2->next;
                prev = prev->next;
            }
        }
        delete rhead;
        delete ret;
    }
};

4、23. 合并 K 个升序链表

 思路:把所有的头结点放进⼀个⼩根堆(使用优先级队列实现)中,这样就能快速的找到每次 K 个链表中最⼩的元素是哪个。

/**
 * 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:
    struct cmp {
        bool operator()(const ListNode* a, const ListNode* b) {
            return a->val > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, cmp> heap;
        for (auto l : lists) {
            if (l)
                heap.push(l);
        }
        ListNode* ret = new ListNode(0);
        ListNode* prev = ret;
        while (!heap.empty()) {
            ListNode* t = heap.top();
            heap.pop();
            prev->next = t;
            prev = t;
            if (t->next)
                heap.push(t->next);
        }
        prev = ret->next;
        delete ret;
        return prev;
    }
};
  1. 定义一个比较结构体cmp,用于比较两个节点的值大小,确保优先级队列是一个最小堆。
  2. 遍历输入的链表数组lists,将每个链表的头节点(如果不为空)加入到优先级队列heap中。
  3. 创建一个哑节点ret,它将作为返回的链表的头节点的前驱,用于简化链表操作。同时,使用一个指针prev来跟踪当前链表的最后一个节点。
  4. heap不为空时,循环执行以下操作:
    • heap中取出最小值节点t(即优先级队列的顶部元素),这是当前所有链表头节点中值最小的节点。
    • prevnext指向t,将t接入到当前构建的链表中。
    • 更新prev指向t,即将prev移动到链表的最末端。
    • 如果t还有下一个节点(t->next不为空),则将这个下一个节点加入到heap中,以便继续参与后续的比较和选择过程。
  5. 循环结束后,所有输入的链表已经完全合并到了由ret->next开始的链表中。
  6. 在返回结果之前,首先保存ret->next到一个临时变量prev(这里重新使用prev变量来简化代码,其实是返回链表的头节点),然后删除哑节点ret
  7. 返回prev,即合并后的链表的头节点。

思路二:递归/分治 

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

    ListNode* merge(vector<ListNode*>& lists, int left, int right) {
        int mid = left + right >> 1;
        if (left > right)
            return nullptr;
        if (left == right)
            return lists[left]; // 只有一个链表

        ListNode* l1 = merge(lists, left, mid);
        ListNode* l2 = merge(lists, mid + 1, right);

        return mergeTwoList(l1, l2);
    }

    ListNode* mergeTwoList(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr)
            return l2;
        if (l2 == nullptr)
            return l1;

        ListNode head;
        ListNode *cur1 = l1, *cur2 = l2, *prev = &head;
        head.next = nullptr;

        while (cur1 && cur2) {
            if (cur1->val <= cur2->val) {
                prev = prev->next = cur1;
                cur1 = cur1->next;
            } else {
                prev = prev->next = cur2;
                cur2 = cur2->next;
            }
        }

        if (cur1)
            prev->next = cur1;
        if (cur2)
            prev->next = cur2;

        return head.next;
    }
};

5、25. K 个一组翻转链表

 思路:先求出需要逆序的组数n,重复n次长度为k的链表逆序,通过头插到新链表实现逆序,每头插k个元素后更新头插位置。

/**
 * 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* reverseKGroup(ListNode* head, int k) {
        int n = 0;
        ListNode* cur = head;
        while (cur) {
            cur = cur->next;
            n++;
        }
        n /= k;
        ListNode* newhead = new ListNode(0);
        ListNode* prev = newhead;
        cur = head;
        for (int i = 0; i < n; i++) {
            ListNode* tmp = cur;
            for (int j = 0; j < k; j++) {
                ListNode* next = cur->next;
                cur->next = prev->next;
                prev->next = cur;
                cur = next;
            }
            prev = tmp;
        }
        prev->next = cur;
        cur = newhead->next;
        delete newhead;
        return cur;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1494953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用nvidia-ml-py事实监控GPU状态

平时监控GPU状态最常用的是watch配合nvidia-smi指令&#xff0c;但有时可能不仅仅需要监控&#xff0c;还需要记录状态数据&#xff0c;比如GPU的显存变化以及利用率变化等等。本文提供了一个使用nvidia-ml-py包编写的简易Demo&#xff0c;该Demo能够实现简易版的nvidia-smi功能…

Linux网络隧道协议IPIP认知(基于Linux network namespace 的 IPIP 隧道通信)

写在前面 博文内容为 Linux 隧道通信 IPIP认知内容涉及&#xff1a;ipip 介绍&#xff0c;一个 ipip 通信 Demo 以及数据帧流转分析理解不足小伙伴帮忙指正 某些人和事&#xff0c;哪怕没有缘分&#xff0c;是路边的风景&#xff0c;可是只要看一眼&#xff0c;依然会让人觉得…

Java中使用Jsoup实现网页内容爬取与Html内容解析并使用EasyExcel实现导出为Excel文件

场景 Pythont通过request以及BeautifulSoup爬取几千条情话&#xff1a; Pythont通过request以及BeautifulSoup爬取几千条情话_爬取情话-CSDN博客 Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本&#xff1a; Node-RED中使用html节点爬取HTML网页资料之爬…

mybatis单表curd笔记(尚硅谷

Mybatis 11111ibatis和mybatis不同 查询文档mybatis的日志输出id赋值输入&#xff08;向sql语句传入数据单个简单类型单个实体对象多个简单类型map类型 输出数据的指定单个简单类型单个实体类型输出map类型输出list输出类型主键回显&#xff08;自增长类型主键回显&#xff08;…

强大的ps 命令 -o 自定义输出内容选项

强大的ps 命令 -o 自定义输出内容选项 1、ps命令介绍和作用2、问题描述 1、ps命令介绍和作用 ps 是一个 Unix 和类 Unix 操作系统中常用的命令&#xff0c;用于显示当前运行的进程信息。ps 命令的作用包括&#xff1a; 查看进程信息&#xff1a; ps 命令可以列出当前系统中正…

【自然语言处理】【大模型】BitNet:用1-bit Transformer训练LLM

BitNet&#xff1a;用1-bit Transformer训练LLM 《BitNet: Scaling 1-bit Transformers for Large Language Models》 论文地址&#xff1a;https://arxiv.org/pdf/2310.11453.pdf 相关博客 【自然语言处理】【大模型】BitNet&#xff1a;用1-bit Transformer训练LLM 【自然语言…

Matlab梁单元有限元编程 | 铁木辛柯梁 | 欧拉梁 | Matlab源码 | 理论文本

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

【网络安全】漏洞挖掘入门教程(非常详细),小白是如何挖漏洞(技巧篇)0基础入门到精通!

温馨提示&#xff1a; 初学者最好不要上手就去搞漏洞挖掘&#xff0c;因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫&#xff0c;而且难度较大…… 较合理的途径应该从漏洞利用入手&#xff0c;不妨分析一些公开的CVE漏洞。很多漏洞都有比较好的资料&#xff0c;分…

手写分布式配置中心(四)增加实时刷新功能(长轮询)

上一篇文章中实现了短轮询&#xff0c;不过短轮询的弊端也很明显&#xff0c;如果请求的频率较高&#xff0c;那么就会导致服务端压力大&#xff08;并发高&#xff09;&#xff1b;如果请求的频率放低&#xff0c;那么客户端感知变更的及时性就会降低。所以我们来看另一种轮询…

总结归纳Kubernetes | 一站式速查知识,助您轻松驾驭容器编排技术(水平扩展控制)

Kubernetes&#xff0c;亦被称为K8s&#xff0c;是业界公认的容器编排巨擘&#xff0c;以其卓越的能力简化了容器化应用的部署、扩展和管理流程。通过其强大的功能&#xff0c;Kubernetes不仅提升了应用的可靠性和可伸缩性&#xff0c;还优化了资源利用率&#xff0c;为开发者和…

MM配置1-定义、复制、删除、检查工厂

配置步骤&#xff0c;如下图&#xff1a; 双击“复制&#xff0c;删除&#xff0c;检查工厂选项” 点击“复制”按钮&#xff0c;输入参考工厂&#xff0c;和要新建的工厂 复制完成后&#xff0c;返回到上一界面&#xff0c;双击“定义工厂”选项 选中新建的1070工厂&#xff0…

java常用技术栈,java面试带答案

前言 我们从一个问题引入今天的主题。 在日常业务开发中&#xff0c;我们可能经常听到 DBA 对我们说“不要”&#xff08;注意&#xff1a;不是禁止&#xff09;使用 join&#xff0c;那么为什么 DBA 对 join 这么抵触呢&#xff1f;是 join 本身有问题&#xff0c;还是我们使…

HarmonyOS 数据持久化之首选项 preferences

接下来 我们来说说数据持久化的问题 我们平时处理的数据都是在内存中处理的 我们应用一点重启 所有数据都消失了 肯恩是不符合一些场景的 harmonyos中 提供了比较多的解决方案 最多的两种是 用户首选项 关系型数据库 本文的话 我们就来看看 用户首选项 首先&#xff0c;什么…

Android开发新手入门教程,android笔试面试题

前言 尤其是在最近一段时间内&#xff0c;感觉一天天的时间过得又慢又快&#xff0c;慢的是感觉复工了以后在公司的8.9个小时简直算是煎熬了&#xff0c;快的是常常感觉时间一天天&#xff0c;一月月的过去了&#xff0c;可是发现自己还在原路踏步走。看似每天忙成狗&#xff…

【数学建模】层次分析

1.建立递阶层次结构模型 2.构造出各层次中的所有判断矩阵 对指标的重要性进行两两比较&#xff0c;构造判断矩阵&#xff0c;科学求出权重 矩阵中元素aij的意义是&#xff0c;第i个指标相对第j个指标的重要程度 对角线1&#xff0c;aijaji1 矛盾——>一致性检验

win11配置Mask DINO小白踩坑记录

win11配置Mask DINO踩坑记录 1 准备工作2 创建python环境和安装detectron22.1 安装前提2.2 安装流程2.2.1 cl.exe的错误2.2.2 SetuptoolsDeprecationWarning的错误 3 MaskDINO运行3.1 运行demo 前情提要&#xff1a;需要复现Mask DINO&#xff0c;但是实验室没有Linux的电脑&am…

+++

解法&#xff1a; 显然a可以为aik&#xff08;i为整数&#xff09;&#xff0c;b可以为bjk(j为整数&#xff09;。 若aikbjk。假定i>j&#xff0c;那么a<b。可以得到b-a(i-j)k 我是傻逼&#xff0c;不放代码了 #include<iostream> #include<vector> #inc…

Tomcat基础与Nginx的动静分离

一、TOMCAT基础功能 &#xff08;一&#xff09;自动解压war包 在配置文件中讲到&#xff0c;当接受到请求后&#xff0c;会匹配符合要求的Host&#xff0c;在配置文件中的Host只有一个&#xff0c;且规定了自动解压war包 自动解压war包 .war&#xff1a;WebApp打包,类zip格…

【ESP32 IDF】SPI层次结构SPI协议与SPI控制器结构

文章目录 前言一、SPI 程序层次1.1 硬件原理图1.2 硬件框图1.3 软件层次 二、SPI协议2.1 硬件连线2.2 如何访问SPI设备2.3 SPI 框图 总结 前言 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种常见的串行通信协议&#xff0c;用于在微控制器和外部设备之间进行…

Qt QtCreator打开pro项目时出现假死现象

在Windows系统下&#xff0c;QtCreator打开pro项目时出现假死现象&#xff0c;左侧项目树形图无法展开&#xff0c;项目根节点一直在转圈。尝试关掉所有QtCreator进程&#xff0c;重新打开pro也是无济于事。 解决方案&#xff1a; 打开“运行”窗口&#xff08;快捷键&#x…