C++优选算法九 链表

一、常用技巧

  1. 画图!直观形象,便于理解。
  2. 引入虚拟“头”结点。
  3. 不吝啬空间。
  4. 快慢双指针:
  •         判环
  •         找链表中环的入口
  •         找链表中倒数第n个结点

二、常用操作

  1. 创建一个新结点
  2. 尾插
  3. 头插

三、示例题目 

1.两数相加. - 力扣(LeetCode) 

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

解法(模拟):
算法思路:
两个链表都是逆序存储数字的,即两个链表的个位数、十位数等都已经对应,可以直接相加。在相加过程中,我们要注意是否产生进位,产生进位时需要将进位和链表数字一同相加。如果产生进位的位置在链表尾部,即答案位数比原链表位数长一位,还需要再 new 一个结点储存最高位。

class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int ret=0;ListNode *head=new ListNode(0);//创建一个虚拟头结点ListNode*phead=head;while(l1&&l2){ret+=l1->val;ret+=l2->val;ListNode*node=new ListNode(ret%10);ret/=10;phead->next=node;phead=node;l1=l1->next;l2=l2->next;}while(l1)//处理剩下的结点{ret+=l1->val;ListNode*node=new ListNode(ret%10);phead->next=node;phead=node;ret/=10;l1=l1->next;}while(l2)//处理剩下的结点{ret+=l2->val;ListNode*node=new ListNode(ret%10);phead->next=node;phead=node;ret/=10;l2=l2->next;}if(ret!=0){phead->next=new ListNode(ret);}return head->next;}
};

 2.两两交换链表中的结点. - 力扣(LeetCode)

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

解法(模拟)

 

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=nnext;if(cur)next=cur->next;if(next)nnext=next->next;}cur=newHead->next;delete newHead;return cur;}
};

3.重排链表. - 力扣(LeetCode)

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[1,4,2,3]

示例 2:

输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]

解法:
算法思路:画图画图画图,重要的事情说三遍~

  1. 找中间节点;(快慢双指针)
  2. 中间部分往后的逆序;(双/三指针、头插法)
  3. 合并两个链表。(双指针)
class Solution {
public:void reorderList(ListNode* head){if (head == nullptr || head->next == nullptr)return;//快慢指针找中间节点ListNode* slow = head, * fast = head;while (fast != nullptr&&fast->next!=nullptr){slow = slow->next;fast = fast->next->next;}ListNode* pphead = head;while (pphead->next != slow){pphead = pphead->next;}pphead->next = nullptr;//逆序后半部分ListNode* newhead = new ListNode(0);ListNode* node = newhead;ListNode* s = slow;ListNode* ss = slow;while (s){s = s->next;slow->next = newhead;newhead = slow;slow = s;}delete(node);node = nullptr;ss->next = nullptr;//合并链表ListNode* phead = new ListNode(0);ListNode* newnode = phead;while (head && newhead){phead->next = head;head = head->next;phead = phead->next;phead->next = newhead;phead = phead->next;newhead = newhead->next;}head = newnode->next;delete(newnode);}
};

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

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[1->4->5,1->3->4,2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

解法一(利用堆)
算法思路:

合并两个有序链表是比较简单的,就是用双指针依次比较链表 1、链表 2 未排序的最小元素,选择更小的那一个加入有序的答案链表中。

合并 K 个升序链表时,我们依旧可以选择 K 个链表中,头结点值最小的那一个。那么如何快速的得到头结点最小的是哪一个呢?用堆这个数据结构就好,我们可以把所有的头结点放进一个小根堆中,这样就能快速的找到每次 K 个链表中,最小的元素是哪个。

class Solution {
public:class compere{public:bool operator()(ListNode* n1, ListNode* n2){return n1->val > n2->val;}};ListNode* mergeKLists(vector<ListNode*>& lists) {int count=0;for(auto e:lists){if(e==nullptr)count++;}if(count==lists.size())return nullptr;//创建一个小根堆,自己设置比较规则,按结点中的值进行比较priority_queue<ListNode*, vector<ListNode*>, compere> myHeap;ListNode* head = new ListNode(0);ListNode* phead = head;//让所有头结点进入小根堆for (auto e : lists){if(e!=nullptr)myHeap.push(e);}//合并K个有序链表while (!myHeap.empty()){ListNode* node = myHeap.top();phead->next = node;phead = node;myHeap.pop();node = node->next;if (node == nullptr)continue;myHeap.push(node);}return head->next;}
};

解法二(递归/分治)
算法思路:

逐一比较时,答案链表越来越长,每个跟它合并的小链表的元素都需要比较很多次才可以成功排序。比如,我们有8个链表,每个链表长为 100。逐一合并时,我们合并链表的长度分别为(0,100),(100,100),(200,100),(300,100),(400,100),(500,100),(600,100),(700,100)。所有链表的总长度共计 3600。如果尽可能让长度相同的链表进行两两合并呢?这时合并链表的长度分别是(100,100)x4,(200,200)x2,(400,400),共计 2400。比上一种的计算量整整少了 1/3。迭代的做法代码细节会稍多一些,这里给出递归的实现,代码相对洁,不易写错。
算法流程:
1.特判,如果题目给出空链表,无需合并,直接返回;
2.返回递归结果。
递归函数设计:

  1. 递归出口: 如果当前要合并的链表编号范围左右值相等,无需合并,直接返回当前链表;
  2. 应用二分思想,等额划分左右两段需要合并的链表,使这两段合并后的长度尽可能相等;
  3. 对左右两段分别递归,合并 [ l , r ] 范围内的链表;
  4. 再调用 mergeTwoLists 函数进行合并(就是合并两个有序链表)。
    class Solution {
    public:ListNode* mergeKLists(vector<ListNode*>& lists) {return merge(lists,0,lists.size()-1);}ListNode* merge(vector<ListNode*>& lists,int left,int right){if(left>right)return nullptr;if(left==right)return lists[left];//1.平分数组int mid=(left+right)>>1;//2.递归处理左右区间ListNode*l1=merge(lists,left,mid);ListNode*l2=merge(lists,mid+1,right);//合并两个有序链表return mergeTowList(l1,l2);}ListNode*mergeTowList(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.K个一组翻转链表. - 力扣(LeetCode)

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例 2:

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

解法(模拟)
算法思路:

本题的目标非常清晰易懂,不涉及复杂的算法,只是实现过程中需要考虑的细节比较多。

我们可以把链表按 K 个为一组进行分组,组内进行反转,并且记录反转后的头尾结点,使其可以和前、后连接起来。思路比较简单,但是实现起来是比较复杂的。

我们可以先求出一共需要逆序多少组(假设逆序 n 组),然后重复 n 次长度为 k 的链表的逆序即可。

 

class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {//1.求出需要逆序多少组ListNode*phead=head;int n=0;while(phead){n++;phead=phead->next;}n=n/k;//2.重复n次:长度为K的链表的逆序即可ListNode*node=new ListNode(0);ListNode*prev=node;ListNode*tmp=nullptr;ListNode*next=nullptr;for(int i=0;i<n;i++){tmp=head;for(int j=0;j<k;j++){next=head->next;head->next=prev->next;prev->next=head;head=next;}prev=tmp;}//3.把不需要翻转的链接上if(head){tmp->next=head;}ListNode*newnode=node->next;delete node;node=nullptr;return newnode;}
};

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

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

相关文章

计算机网络:网络层 —— 虚拟专用网 VPN

文章目录 虚拟专用网 VPN 概述内联网 VPN外联网 VPN 虚拟专用网 VPN 概述 虚拟专用网&#xff08;Virtual Private Network&#xff0c;VPN&#xff09;&#xff1a;利用公用的因特网作为本机构各专用网之间的通信载体&#xff0c;这样形成的网络又称为虚拟专用网。 出于安全…

Web 安全基础知识梳理大全,零基础入门到精通,收藏这篇就够了

一、各种linux虚拟机忘记密码 1、红帽忘记密码修改root密码 1 在重启的时候 e 进入 2 在linux16 后面找到UTF-8 在后面加 rd.break 然后ctrlx 3 这时候可以输入mount 看一下 会发现根为 /sysroot/ 没有w权限&#xff0c;只有ro权限 4 输入 mount -o remount,r…

非凸科技助力第49届ICPC亚洲区域赛(成都)成功举办

10月26日-27日&#xff0c;由电子科技大学承办、非凸科技与华为共同支持的第49届ICPC国际大学生程序设计竞赛亚洲区域赛&#xff08;成都&#xff09;在郫都区体育中心体育馆顺利举行。非凸科技期待与产学研各界专家、青年才俊一起&#xff0c;推动基础科学理论研究的重大突破&…

ssm051网上医院预约挂号系统+jsp(论文+源码)_kaic

本科毕业设计论文 题目&#xff1a;网上医院预约挂号系统设计与实现 系 别&#xff1a; XX系&#xff08;全称&#xff09; 专 业&#xff1a; 软件工程 班 级&#xff1a; 软件工程15201 学生姓名&#xff1a; 学生学号&#xff1a; 指导教师&#xff1a…

EtherCAT转ModbusTCP相关技术

EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ftt&id822721028899 MS-GW15 概述 MS-GW15 是 EtherCAT 和 Modbus TCP 协议转换网关&#xff0c;为用户提供一种 PLC 扩展的集成解决方案&#xff0c;可以轻松容易将 Modbu…

qt QTextStream详解

1、概述 QTextStream类是Qt框架中用于处理文本输入输出的类。它提供了一种方便的方式&#xff0c;可以从各种QIODevice&#xff08;如QFile、QBuffer、QTcpSocket等&#xff09;中读取文本数据&#xff0c;或者将文本数据写入这些设备中。QTextStream能够自动处理字符编码的转…

大数据-201 数据挖掘 机器学习理论 - 决策树 局部最优 剪枝 分裂 二叉分裂

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

项目_Linux_网络编程_私人云盘

概述 项目功能总述&#xff1a; 该项目使用TCP进行通信&#xff0c;实现文件的上传和下载。云盘的文件同步有手动同步、实时同步、定时同步这三种。本项目主要实现的是手动同步的功能&#xff0c;重点训练在如何使用TCP进行文件传输。 选择TCP的原因&#xff1a; 文件的传输…

细腻的链接:C++ list 之美的解读

细腻的链接&#xff1a;C list 之美的解读 前言&#xff1a; 小编在前几日刚写过关于vector容器的内容&#xff0c;现在小编list容器也学了一大部分了&#xff0c;小编先提前说一下学这部分的感悟&#xff0c;这个部分是我学C以来第一次感到有难度的地方&#xff0c;特别是在…

Java之包,抽象类,接口

目录 包 导入包 静态导入 将类放入包 常见的系统包 抽象类 语法规则 注意事项&#xff1a; 抽象类的作用 接口 实现多个接口 接口间的继承 接口使用实例 &#xff08;法一&#xff09;实现Comparable接口的compareTo()方法 &#xff08;法二&#xff09;实现Comp…

qt QDragEnterEvent详解

1、概述 QDragEnterEvent是Qt框架中用于处理拖放进入事件的一个类。当用户将一个拖拽对象&#xff08;如文件、文本或其他数据&#xff09;拖动到支持拖放操作的窗口部件&#xff08;widget&#xff09;上时&#xff0c;系统会触发QDragEnterEvent事件。这个类允许开发者在拖拽…

永恒之蓝漏洞复现

永恒之蓝漏洞复现 1 实验准备 1台靶机 win7 关闭防火墙 控制面板->系统和安全->Windows 防火墙 192.168.184.131 1台攻击者 kali 192.168.184.129 2 实施攻击 kali操作 1.输入msfconsole回车 2.搜索ms17_010模块 msf6 > search ms17_010 3.选择编号为3的模块 use 3…

c++拷贝构造函数

1.拷贝构造函数 拷贝构造函数的调用时机 class A { public://默认构造函数A(){m_Hp 100;cout << "A默认构造函数调用完毕" << endl;}//有参构造函数A(int hp){m_Hp hp;cout << "A有参构造函数调用完毕" << endl;}A(const A&…

排序算法的分类、时间空间复杂度

排序是计算机科学和数学中的基本操作&#xff0c;有多种不同的方式&#xff0c;每种方式都有其特定的时间复杂度和空间复杂度。以下是对排序方式的分类及其时间复杂度和空间复杂度的详细分析&#xff1a; 一、排序方式的分类 排序方式主要分为两大类&#xff1a;比较排序和非…

【MMAN-M2】基于缺失模态编码器的多多头关注网络

abstract&#xff1a; 多模态融合是多模态学习领域的研究热点。以往的多模态融合任务大多是基于完整模态的。现有的缺失多模态融合研究没有考虑模态的随机缺失&#xff0c;缺乏鲁棒性。大多数方法都是基于缺失模态和非缺失模态之间的相关性&#xff0c;而忽略了缺失模态的语境…

【AI绘画】Stable Diffusion 基础教程! 如何写出好的prompt,一些技巧和原则

前言 Stable Diffusion 教程-中文 Ask AI for ART Original txt2img and img2img modes 基础模式之 文生图/图生图 基础入门部分 所有的AI设计工具&#xff0c;安装包、模型和插件&#xff0c;都已经整理好了&#xff0c;&#x1f447;获取~ 输入一段话&#xff0c;生成一…

C++ —— 网络通信

之前在Linux系统下介绍了多种实现网络通信的方式&#xff0c;从本文开始后面的文章将在Windows系统下用C为大家介绍技术&#xff0c;敬请期待~。 话不多说&#xff0c;直接进入正文&#xff0c;我们知道&#xff0c;要完成网络通信要用到非常多的函数&#xff0c;并且函数的参数…

FPGA视频GTH 8b/10b编解码转PCIE3.0传输,基于XDMA中断架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案我已有的 GT 高速接口解决方案 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图输入Sensor之-->芯片解码的HDMI视频数据组包基于GTH高速接口的视频传输架构GTH IP 简介GTH 基本结构GTH 发送和接收处理…

java基础之 String\StringBuffer\ StringBuilder

文章目录 String字符串的创建为什么说String是不可变的&#xff1f;创建后的字符串存储在哪里&#xff1f;字符串的拼接String类的常用方法 StringBuilder & StringBuffer使用方法验证StringBuffer和StringBuilder的线程安全问题 总结三者区别什么情况下用运算符进行字符串…

深度解析阿里的Sentinel

1、前言 这是《Spring Cloud 进阶》专栏的第五篇文章&#xff0c;这篇文章介绍一下阿里开源的流量防卫兵Sentinel&#xff0c;一款非常优秀的开源项目&#xff0c;经过近10年的双十一的考验&#xff0c;非常成熟的一款产品。 文章目录如下&#xff1a; 2、什么是sentinel&…