【优选算法】(第二十七篇)
目录
重排链表(medium)
题目解析
讲解算法原理
编写代码
合并K个升序链表(hard)
题目解析
讲解算法原理
编写代码
重排链表(medium)
题目解析
1.题目链接:. - 力扣(LeetCode)
2.题目描述
给定⼀个单链表 L 的头节点 head ,单链表 L 表⽰为:L(0)→L(1)→…→L(n-1)→L(n)
请将其重新排列后变为:
L(0)→L(n)→L(1)→L(n-1)→L(2)→L(n-2)→…
不能只是单纯的改变节点内部的值,⽽是需要实际的进⾏节点交换。
⽰例1:
输⼊:head=[1,2,3,4]
输出:[1,4,2,3]
⽰例2:
输⼊:head=[1,2,3,4,5]
输出:[1,5,2,4,3]
提⽰:
• 链表的⻓度范围为 [1, 5 * 10(4)]
• 1 <= node.val <= 1000
讲解算法原理
解法:
算法思路:
画图画图画图,重要的事情说三遍~
1. 找中间节点;
2. 中间部分往后的逆序;
3. 合并两个链表
编写代码
c++算法代码:
/*** 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;// 1. 找到链表的中间节点 - 快慢双指针(⼀定要画图考虑 slow 的落点在哪⾥) ListNode* slow = head, *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}// 2. 把 slow 后⾯的部分给逆序 - 头插法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* cur1 = head, *cur2 = head2->next;while(cur1){// 先放第⼀个链表prev->next = cur1;cur1 = cur1->next;prev = prev->next;// 再放第⼆个链表if(cur2){prev->next = cur2;prev = prev->next;cur2 = cur2->next;}}delete head2;delete ret;}
};
java算法代码:
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution
{public void reorderList(ListNode head) {// 处理边界情况if(head == null || head.next == null || head.next.next == null) return;// 1. 找链表的中间节点 - 快慢双指针(⼀定要画图分析 slow 的落点)ListNode slow = head, fast = head;while(fast != null && fast.next != null){slow = slow.next;fast = fast.next.next;}// 2. 把 slow 后⾯的部分给逆序 - 头插法ListNode head2 = new ListNode(0);ListNode cur = slow.next;slow.next = null; // 把两个链表分离while(cur != null){ListNode next = cur.next;cur.next = head2.next;head2.next = cur;cur = next;}// 3. 合并两个链表 - 双指针ListNode cur1 = head, cur2 = head2.next;ListNode ret = new ListNode(0);ListNode prev = ret;while(cur1 != null){// 先放第⼀个链表prev.next = cur1;prev = cur1;cur1 = cur1.next;// 在合并第⼆个链表if(cur2 != null){prev.next = cur2;prev = cur2;cur2 = cur2.next;}}}
}
合并K个升序链表(hard)
题目解析
1.题目链接:. - 力扣(LeetCode)
2.题目描述
给你⼀个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到⼀个升序链表中,返回合并后的链表。
⽰例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=[[]]输出:[]
提⽰:k==lists.length0<=k<=10^40<=lists[i].length<=500-10^4<=lists[i][j]<=10^4lists[i]按升序排列
lists[i].length的总和不超过10^4
讲解算法原理
解法⼀(利⽤堆):
算法思路:
合并两个有序链表是⽐较简单且做过的,就是⽤双指针依次⽐较链表 1 、链表 2 未排序的最⼩元素,选择更⼩的那⼀个加⼊有序的答案链表中。
合并 K 个升序链表时,我们依旧可以选择 K 个链表中,头结点值最⼩的那⼀个。那么如何快速的得到头结点最⼩的是哪⼀个呢?⽤堆这个数据结构就好啦~
我们可以把所有的头结点放进⼀个⼩根堆中,这样就能快速的找到每次 K 个链表中,最⼩的元素是哪个。
解法⼆(递归/分治):
算法思路:
逐⼀⽐较时,答案链表越来越⻓,每个跟它合并的⼩链表的元素都需要⽐较很多次才可以成功排序。⽐如,我们有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函数进⾏合并(就是合并两个有序链表)
编写代码
解法一代码:
c++算法代码:
/*** 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
{struct cmp{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;// 让所有的头结点进⼊⼩根堆for(auto l : lists)if(l) heap.push(l);// 合并 k 个有序链表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;}
};
java算法代码:
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution
{public ListNode mergeKLists(ListNode[] lists) {PriorityQueue<ListNode> heap = new PriorityQueue<>((v1, v2) -> v1.val
- v2.val);// 将所有头结点加⼊到⼩根堆中for(ListNode l : lists)if(l != null)heap.offer(l);// 合并ListNode ret = new ListNode(0);ListNode prev = ret;while(!heap.isEmpty()){ListNode t = heap.poll();prev.next = t;prev = t;if(t.next != null) heap.offer(t.next);}return ret.next;}
}
解法二代码:
c++算法代码:
/*** 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* 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;// [left, mid] [mid + 1, right]// 2. 递归处理左右区间ListNode* l1 = merge(lists, left, mid);ListNode* l2 = merge(lists, mid + 1, right);// 3. 合并两个有序链表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;}
};
java算法代码:
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution
{public ListNode mergeKLists(ListNode[] lists) {return merge(lists, 0, lists.length - 1);}public ListNode merge(ListNode[] lists, int left, int right){if(left > right) return null;if(left == right) return lists[left];// 1. 平分数组int mid = (left + right) / 2;// [left, mid] [mid + 1, right]// 2. 递归处理左右两部分ListNode l1 = merge(lists, left, mid);ListNode l2 = merge(lists, mid + 1, right);// 3. 合并两个有序链表return mergeTwoList(l1, l2);}public ListNode mergeTwoList(ListNode l1, ListNode l2){if(l1 == null) return l2;if(l2 == null) return l1;// 合并两个有序链表ListNode head = new ListNode(0);ListNode cur1 = l1, cur2 = l2, prev = head;while(cur1 != null && cur2 != null){if(cur1.val <= cur2.val){prev.next = cur1;prev = cur1;cur1 = cur1.next;}else{prev.next = cur2;prev = cur2;cur2 = cur2.next;}}if(cur1 != null) prev.next = cur1;if(cur2 != null) prev.next = cur2;return head.next;}
}
相关文章:
【优选算法】(第二十七篇)
目录 重排链表(medium) 题目解析 讲解算法原理 编写代码 合并K个升序链表(hard) 题目解析 讲解算法原理 编写代码 重排链表(medium) 题目解析 1.题目链接:. - 力扣(LeetCod…...
学习Flask框架
Flask简介 Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权。 Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没…...
Elasticsearch:使用 LLM 实现传统搜索自动化
作者:来自 Elastic Han Xiang Choong 这篇简短的文章是关于将结构化数据上传到 Elastic 索引,然后将纯英语查询转换为查询 DSL 语句,以使用特定过滤器和范围搜索特定条件。完整代码位于此 Github repo 中。 首先,运行以下命令安装…...
人脸表情行为识别系统源码分享
人脸表情行为识别系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…...
ThreadLocal原理解析及面试
基本使用 讲原理之前,我简单写个demo小程序说说怎么使用 public class TestThreadLocal {public static void main(String[] args) throws InterruptedException {ThreadLocal<String> tl new ThreadLocal();/**主线程设置了一个值*/tl.set("SSSSSs&…...
探索未来:mosquitto-python,AI领域的新宠
文章目录 探索未来:mosquitto-python,AI领域的新宠背景:为何选择mosquitto-python?库简介:mosquitto-python是什么?安装指南:如何安装mosquitto-python?函数用法:5个简单…...
C++版iwanna1
第一篇目录 开头程序Game.cpp源文件Player.h头文件Player.cpp源文件trigger.h头文件trigger.cpp源文件Cmp.h头文件Cmp.cpp源文件 开头 大家好,我叫这是我58。 程序 Game.cpp源文件 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include <c…...
LSTM变种模型
一、GRU 1.概念 GRU(门控循环单元,Gated Recurrent Unit)是一种循环神经网络(RNN)的变体,旨在解决标准 RNN 在处理长期依赖关系时遇到的梯度消失问题。GRU 通过引入门控机制简化了 LSTM(长短期…...
Python进阶--函数进阶
目录 1. 函数多返回值 2. 函数多种传参方式 (1). 位置参数 (2). 关键字参数 (3). 缺省参数 (4). 不定长参数 3. 匿名函数 (1). 函数作为参数传递 (2). lambda匿名函数 1. 函数多返回值 def return_num():return 1# 返回1之后就不会再向下继续执行函数体return 2 resu…...
elasticsearch 8.2 设置账号密码
背景:单节点集群数据写入测试-CSDN博客 前述项目支持设置账号密码,但8+版本似乎不能那么做了。 ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. bootstrap check failure [1] of…...
JavaScript代码如何测试?
测试JavaScript代码是确保其功能、性能和可靠性的关键步骤。以下是一些详细的步骤和方法,用于测试JavaScript代码: 1、编写测试用例 首先,你需要为要测试的JavaScript代码编写测试用例。这些用例应该涵盖代码的各种功能和场景,包…...
案例分享—国外ui设计优秀案例
国外企业更注重用户体验设计,倾向于简洁清晰的设计风格,以提高用户的使用体验和操作效率。他们注重“简约至上”的设计理念,认为简洁的设计可以减少用户的认知负担,提高用户的工作效率。 设计师在界面设计中往往更加注重创意性和个…...
在JavaScript中,改变this指向的call,apply,bind有什么区别,原理分别是什么?
在JavaScript中,call、apply和bind方法都是用来改变函数执行时this指向的。 以下通过一个Demo帮助理解,代码如下: var obj {name: lisi,sayHello: function() {console.log(this.name)} } obj.sayHello()// lisifunction sayHello() {conso…...
Redis 缓存策略详解:提升性能的四种常见模式
在现代分布式系统中,缓存是提升性能和减轻数据库负载的关键组件。Redis 作为一种高性能的内存数据库,被广泛应用于缓存层。本文将深入探讨几种常用的 Redis 缓存策略,包括旁路缓存模式(Cache-Aside Pattern)、读穿透模…...
怎么建设网站吸引并留住客户
如何建设网站吸引并留住客户 在当今数字化时代,网站是企业与客户沟通的重要桥梁。一个设计精良、功能完备的网站不仅能吸引客户的注意,还能有效留住他们。以下是一些建设网站的关键策略。 **1. 用户体验优先** 网站的整体用户体验(UX&#x…...
培训行业为什么要搭建自己的知识付费小程序平台?集师知识付费系统 集师知识付费小程序 集师知识服务系统 集师线上培训系统 集师线上卖课小程序
在当今这个信息爆炸的时代,培训行业正面临前所未有的变革与挑战。传统的线下授课模式虽然经典,但在互联网技术的冲击下,其局限性日益凸显。为了更好地适应市场需求,提升服务效率与用户体验,培训行业亟需搭建自己的知识…...
Linux:Linux进程概念
✨✨✨学习的道路很枯燥,希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 冯诺依曼体系结构 二 操作系统(Operator System) 2.1 概念 2.2 设计OS的目的 编辑 2.3 OS如何进行管理 编辑2.4 总结 三 进程的标示符 3.1 基本概念…...
专题九_递归_算法专题详细总结
目录 递归 1.什么是递归? 2.为什么会用到递归? 3.如何理解递归? 1.递归展开的细节图 2.二叉树中的题目 3.宏观看待递归的过程 1) 不要在意细节的展开图 2) 把递归的函数当作一个黑盒 3) 相信这个黑盒一定能够完成这个任务 4.如何写…...
性能赶超GPT-4!多模态检索最新成果刷爆SOTA!顶会思路确定不学?
关注各大顶会的同学们都知道,今年多模态相关的主题可谓是火爆非常,有许多突破性成果被提出,比如最新的多模态检索增强框架MORE,生成性能猛超GPT-4! 再比如多模态检索模型MARVEL,在所有基准上实现SOTA&…...
基于 Qwen2.5-0.5B 微调训练 Ner 命名实体识别任务
一、Qwen2.5 & 数据集 Qwen2.5 是 Qwen 大型语言模型的最新系列,参数范围从 0.5B 到 72B 不等。 对比 Qwen2 最新的 Qwen2.5 进行了以下改进: 知识明显增加,并且大大提高了编码和数学能力。在指令跟随、生成长文本(超过 8K…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
python基础语法Ⅰ
python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...
AT模式下的全局锁冲突如何解决?
一、全局锁冲突解决方案 1. 业务层重试机制(推荐方案) Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减(自动加全…...
【AI News | 20250609】每日AI进展
AI Repos 1、OpenHands-Versa OpenHands-Versa 是一个通用型 AI 智能体,通过结合代码编辑与执行、网络搜索、多模态网络浏览和文件访问等通用工具,在软件工程、网络导航和工作流自动化等多个领域展现出卓越性能。它在 SWE-Bench Multimodal、GAIA 和 Th…...

