链表leetcode-1

目录

1.常用技巧

1.1引入虚拟头结点

1.2对于变量,不要太吝啬,可以多定义,方便处理

1.3快慢双指针

2.例题

 2.1两数相加

2.2两两交换链表中的节点

2.3重排链表

2.4合并K个升序链表

2.5K个一组翻转链表


1.常用技巧

1.1引入虚拟头结点

可以方便处理边界情况(因为有些题链表提供的是NULL,如果直接引用会报错,如果是循环链表,没有头结点,题目没有其他条件,就很难判断头尾)

方便对链表操作

1.2对于变量,不要太吝啬,可以多定义,方便处理

1.3快慢双指针

可以用于判环,找链表中环的入口,找链表中倒数第N个节点

关于这方面,可以看我这篇文章

链表(c语言版)-CSDN博客

链表的操作无非就是new一个新节点,尾插或头插,或中间插入,或删除。

头插常用于逆序链表

2.例题

 2.1两数相加

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

这题是给的逆序,因为两数相加是从低位开始加,所以反而方便我们操作了。

只要做模拟即可。

利用一个虚拟头结点和尾指针,模拟加法。

下面是我看到题目马上就写出来的,看起来比较繁琐,但是思路比较清晰

class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int jw=0;ListNode*ans=new ListNode(-1);//头结点ListNode*tail=ans;//尾指针while(l1&&l2)//先处理两边都有数{int x=l1->val+l2->val;if(jw)x++,jw=0;if(x>=10)jw++,x-=10;ListNode *tmp=new ListNode(x);tail->next=tmp;tail=tmp;l1=l1->next;l2=l2->next;}while(l1)//处理单个{int x=l1->val;if(jw)x++,jw=0;if(x>=10)jw++,x-=10;ListNode *tmp=new ListNode(x);tail->next=tmp;tail=tmp;l1=l1->next;}while(l2)//处理单个{int x=l2->val;if(jw)x++,jw=0;if(x>=10)jw++,x-=10;ListNode *tmp=new ListNode(x);tail->next=tmp;tail=tmp;l2=l2->next;}while(jw)//处理多的进位{ListNode *tmp=new ListNode(1);tail->next=tmp;tail=tmp;jw--;}return ans->next;}
};

接下来这个版本是优化过,时间复杂度没区别,代码看起来比较简洁

class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode*ans=new ListNode(-1);int x=0;ListNode*tail=ans;while(l1||l2||x){if(l1){x+=l1->val;l1=l1->next;}if(l2){x+=l2->val;l2=l2->next;}tail->next=new ListNode(x%10);x/=10;tail=tail->next;}tail=ans->next;delete ans;return tail;}
};

2.2两两交换链表中的节点

24. 两两交换链表中的节点 - 力扣(LeetCode)

下面的版本是我挺早写的

思路就是利用递归,比如第一个节点的时候,会把第三个节点开始交换后的头结点返回。

然后将第一个节点和第二个节点交换,并把原第一个节点的next指向上面返回的节点。

class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head==nullptr||head->next==nullptr)return head;
//因为当前的一对,只有第一个是非NULL节点,第二个节点是NULL,或者第一个节点就是NULL。
//说明不能进行交换,直接返回第一个节点即可。ListNode*tmp=swapPairs(head->next->next);ListNode*ret=head->next;head->next->next=head;head->next=tmp;return  ret;}
};

接下来是迭代循坏的版本。稍显复杂


class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head==nullptr||head->next==nullptr)return head;//可能只有1一个节点或没有节点ListNode *newhead=new ListNode(0);//虚拟头结点newhead->next=head;ListNode*prev=newhead;//前驱指针ListNode*cur=head;//当前指针ListNode*next=head->next;//当前的下一个指针ListNode*nnext=head->next->next;//当前的下一个的下一个指针while(cur&&next)//只要cur或next其中之一为空,就说明不用交换了。{prev->next=next;next->next=cur;cur->next=nnext;prev=cur;cur=nnext;if(cur)next=nnext->next;//注意原先的nnext可能为空if(next)nnext=next->next;//注意,原先的nnext的下一个指针可能为空}cur=newhead->next;delete newhead;return cur;}
};

2.3重排链表

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

在写这题前,可以先写

876. 链表的中间结点 - 力扣(LeetCode)

206. 反转链表 - 力扣(LeetCode)

21. 合并两个有序链表 - 力扣(LeetCode)

链表(c语言版)-CSDN博客  这篇文章有反转和中间节点。

关于合并有序链表,可以参考合并有序数组,思路没区别

本题的一个思路,就是上面三题的结合


class Solution {
public:void reorderList(ListNode* head) {if(head==nullptr||head->next==nullptr)return;//考虑只有1个节点或没有节点//快慢指针查找中间节点ListNode*fast=head,*slow=head;ListNode*prev=nullptr;while(fast&&fast->next){prev=slow;slow=slow->next;fast=fast->next->next;}prev->next=nullptr;//注意断开链表起始位置和slow开始的部分//开始反转slow开始的部分ListNode*cur=slow,*next=slow->next,*newl2=nullptr,*newl1=head;prev=nullptr;while(cur){if(cur->next==nullptr)newl2=cur;cur->next=prev;prev=cur;cur=next;if(cur)next=next->next;}//开始合并两个有序链表ListNode*rethead=nullptr;ListNode*rettail=nullptr;ListNode*cur1=newl1,*cur2=newl2;while(cur1||cur2){if(cur1){if(rethead==nullptr){rethead=rettail=cur1;}else{rettail->next=cur1;rettail=rettail->next;}cur1=cur1->next;}if(cur2){if(rethead==nullptr){rethead=rettail=cur2;}else{rettail->next=cur2;rettail=rettail->next;}cur2=cur2->next;}}}
};

2.4合并K个升序链表

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

本题有3个思路,第一个思路是暴力,我只在这文字描述,不写了,n^3复杂度,铁出事

暴力思路很简单,就是挑2个链表,进行合并两个有序链表的操作,然后把合并出来的链表,再跟剩下的其中一个链表继续重复操作。直到剩下链表都被合并进去了。

思路2,利用优先队列。假设有k个链表,平均n个节点,每次丢入优先队列都会经历一次log k的操作。所以复杂度O(nk log k)

class Solution {
public://重载下指针的比较,方便优先队列自动排序struct kp {bool operator()(const ListNode*l1,const ListNode*l2) const{return l1->val>l2->val;}};ListNode* mergeKLists(vector<ListNode*>& lists) {priority_queue<ListNode*, vector<ListNode*>, kp>q;int k = lists.size();//返回的链表头结点和尾节点ListNode* rethead = nullptr, *rettail = nullptr;//把链表数组的每个非空头结点放入队列。for(int i=0;i<k;i++){if(lists[i])q.push(lists[i]);}while (!q.empty()){auto tmp = q.top();q.pop();//插入返回的链表if (rethead == nullptr)rethead = rettail = tmp;else{rettail->next = tmp;rettail = rettail->next;}//放入队列if (tmp->next != nullptr){q.push(tmp->next);}}return rethead;}
};

思路3,归并,跟归并排序思路一致,每个链表单独都是一个有序的,每次合并就是把两个有序的链表合并。

每个链表要经历log k次的合并,而一共有k个链表,平均n个节点。复杂度就是n k log k

class Solution {
public:ListNode*merge(vector<ListNode*>&lists,int l,int r){if(l>r)return NULL;if(l==r)return lists[l];int mid=l+(r-l)/2;ListNode*head1=merge(lists,l,mid);ListNode*head2=merge(lists,mid+1,r);ListNode*ret=NULL,*retil=NULL;//合并两个有序链表while(head1&&head2){if(head1->val<head2->val){if(ret==NULL){ret=retil=head1;}else{retil->next=head1;retil=retil->next;}head1=head1->next;}else{if(ret==NULL){ret=retil=head2;}else{retil->next=head2;retil=retil->next;}head2=head2->next;}}while(head1){if(ret==NULL){ret=retil=head1;}else{retil->next=head1;retil=retil->next;}head1=head1->next;}while(head2){if(ret==NULL){ret=retil=head2;}else{retil->next=head2;retil=retil->next;}head2=head2->next;}return ret;}ListNode* mergeKLists(vector<ListNode*>& lists) {srand(time(NULL));return merge(lists,0,lists.size()-1);}
};

2.5K个一组翻转链表

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

本题思路模拟。先求出要逆序多少组。

然后依次逆序即可。

/*** 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) {ListNode*cur=head;int n=0;//先计算链表长度nwhile(cur){n++;cur=cur->next;}//然后计算需要多少组逆序n/=k;//依次开始逆序,利用头插方式cur=head;ListNode*rethead=new ListNode(0);ListNode*prev=rethead,*next=nullptr,*rettail=rethead;for(int i=0;i<n;i++){//每次都头插在prev后面。for(int j=0;j<k;j++){if(j==0)rettail=cur;//记得更新返回链表的末尾next=cur->next;cur->next=prev->next;prev->next=cur;cur=next;}prev=rettail;//prev每次都更新成返回链表的末尾即可}prev->next=cur;//把原链表剩下的内容链接上head=rethead->next;delete rethead;return head;}
};

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

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

相关文章

【HTTP、Web常用协议等等】前端八股文面试题

HTTP、Web常用协议等等 更新日志 2024年9月5日 —— 什么情况下会导致浏览器内存泄漏&#xff1f; 文章目录 HTTP、Web常用协议等等更新日志1. 网络请求的状态码有哪些&#xff1f;1&#xff09;1xx 信息性状态码2&#xff09;2xx 成功状态码3&#xff09;3xx 重定向状态码4&…

场景是人工智能第四要素,是垂直领域人工智能的第一要素。

"场景是人工智能的第四要素&#xff0c;与数据、算力、算法同等重要。"拿着技术找场景&#xff0c;还是拿着场景找技术&#xff1f;这个锤子和钉子的问题&#xff0c;一直困扰着各家AI大厂。从近5年的实践来看&#xff0c;拿着场景找技术是更为稳健的&#xff0c;否则…

哪款宠物空气净化器能更好的清理浮毛?希喂、352、IAM测评分享

家里这三只可爱的小猫咪&#xff0c;已然成为了我们生活中不可或缺的家庭成员&#xff0c;陪伴我们度过了说长不长说短不短的五年时光。时常庆幸自己当年选择养它们&#xff0c;在我失落的时候总能给我安慰&#xff0c;治愈我多时。 但这个温馨的背后也有一点小烦恼&#xff0…

ES6语法详解

以下是ES6常用的一些语法和特性&#xff1a; 声明变量的关键字变化&#xff1a;使用let和const、var来声明变量。 箭头函数&#xff1a;使用箭头&#xff08;>&#xff09;定义函数&#xff0c;简化函数的写法。 模板字符串&#xff1a;使用反引号&#xff08;&#xff0…

Numpy中zeros、ones、empty的用法

目录 numpy基础介绍实例分析及结论 numpy基础介绍 Numpy 补充了Python语言所欠缺的数值计算能力,是其它数据分析及机器学习库的底层库。因其完全标准C语言实现&#xff0c;运行效率充分优化。最重要一点是开源免费。numpy的核心是矩阵&#xff08;即多维数组&#xff09;。 实…

【java入门】关键字、标识符与变量初识

&#x1f680; 个人简介&#xff1a;某大型国企资深软件开发工程师&#xff0c;信息系统项目管理师、CSDN优质创作者、阿里云专家博主&#xff0c;华为云云享专家&#xff0c;分享前端后端相关技术与工作常见问题~ &#x1f49f; 作 者&#xff1a;码喽的自我修养&#x1f9…

Android 14(API 级别 34)中,DexClassLoader 不再支持可写 dex/jar 文件

Android 14&#xff08;API 级别 34&#xff09;中&#xff0c;DexClassLoader 不再支持从可写文件加载 dex/jar 文件。这意味着从Android 14开始&#xff0c;你不能再使用 DexClassLoader 来动态加载位于内部存储中的dex/jar文件&#xff0c;除非这些文件被设置为只读。 解决…

Python统计FreeMind测试用例数量

1.编写背景 由于最近编写迭代测试报告时发现缺少测试用例数量的统计&#xff0c;为了更好地分析迭代测试质量&#xff0c;需统计测试用例与bug的数量占比&#xff0c;故编写此脚本用于统计测试用例的数量(现测试用例编写工具为飞书思维导图&#xff0c;其导出格式为freemind) …

Docker Elasticsearch安装ik分词插件教程

本章教程在通过Docker 安装Elasticsearch,并安装ik分词插件。本文的重点是安装ik分词插件。 一、安装Elasticsearch 安装教程以前写过,参考:https://blog.csdn.net/qq_19309473/article/details/140725121 安装之后,通过http://ip:9200,可以访问,就表示安装成功。 二、安装…

c++学习笔记(5)

151、模板类的示例-栈 示例&#xff1a; #include <iostream> // 包含头文件。 using namespace std; // 指定缺省的命名空间。 // typedef string DataType; // 定义栈元素的数据类型。 template <class DataType> class Stack // 栈类 { private: DataType* item…

Linux终端简单配置(Vim、oh-my-zsh和Terminator)

文章目录 0. 概述1. 完整Vim配置2. Vim配置方案解释2.1 状态行与配色方案2.2 文件管理与缓存设置2.3 搜索与导航优化2.4 缩进与格式化设置2.5 粘贴模式快捷切换2.6 文件编码与格式2.7 性能优化 3. 安装 Oh My Zsh 及配置3.1 安装 Oh My Zsh3.2 Oh My Zsh 配置 3. Terminator终端…

vscode +STM32 VS CODE EXTENSION

stm32 vs code extersion 1.0.0版本可以直接导入cubeide的工程&#xff0c;之后版本不可以&#xff0c;所以为了省事&#xff0c;使用stm32 vs code extersion 1.0.0插件。 安装完stm32 vs code extersion插件&#xff0c;会默认把相关插件一起安装。但是需要手动安装Ninja&am…

交叉编译概念

交叉编译概念 目录 交叉编译概念1. 什么是交叉编译2. 交叉编译的作用3. 交叉编译器4. 交叉编译工具链5. 交叉编译的一般步骤6. 交叉编译实例 1. 什么是交叉编译 交叉编译是指在一个平台上编译代码&#xff0c;使其能够在另一个不同的平台上运行的过程。这种编译方式通常用于开…

Android12——Launcher3文件夹布局修改调整

文章声明&#xff1a;本文是笔者参考良心大佬作品后结合实际需求进行相应的定制&#xff0c;本篇主要是笔者记录一次解析bug笔记&#xff0c;文中可能会引用大佬文章中的部分图片在此声明&#xff0c;并非盈利目的&#xff0c;如涉嫌侵权请私信&#xff0c;谢谢&#xff01; 大…

果蔬识别系统性能优化之路

目录 一级目录二级目录三级目录 前情提要当前问题 优化方案1. 内存化2. 原生化3. 接口化 行动实现结语 一级目录 二级目录 三级目录 前情提要 超详细前端AI蔬菜水果生鲜识别应用优化之路 当前问题 indexddb在webview中确实性能有限&#xff0c;存储量上来后每次读取数据…

【机器学习】交通勘测

交通勘测 交通勘测中的关键应用场景 交通勘测中常用的数据来源 交通勘测中的挑战 结论 &#x1f388;边走、边悟&#x1f388;迟早会好 机器学习在交通勘测中的应用非常广泛&#xff0c;可以用于交通流量预测、事故检测、车辆分类、道路拥堵管理等多个方面。通过结合传感…

什么是函数调用约定?

目录 前言 一、函数调用约定的主要内容 二、常见的函数调用约定 1. __cdecl&#xff08;C Declaration&#xff09; 2. __stdcall&#xff08;Standard Call&#xff09; 3. __fastcall&#xff08;Fast Call&#xff09; 4. __thiscall&#xff08;This Call&#xff0…

【Spring Boot 3】【Web】国际化

【Spring Boot 3】【Web】国际化 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或…

[数据集][目标检测]轮胎检测数据集VOC+YOLO格式4629张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4629 标注数量(xml文件个数)&#xff1a;4629 标注数量(txt文件个数)&#xff1a;4629 标注…

【SQL】删除表中重复数据的方法

很久之前我写入一张sql的数据表&#xff0c;它里面有很多重复的内容。然后我想只保留一条原始数据&#xff1a; 例如上面的时间&#xff0c;出现了很多重复值。 我最初用的是这种方法&#xff1a; SELECT * FROM table_name WHERE primary_key IN (SELECT max(primary_key)F…