网站建设教程 湖南岚鸿/seo怎么优化方案
题目:
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
解法一:
递归解法,自顶向下
链表版二路归并排序(升序,递归版),稳定排序
时间复杂度为 O(n*logn);空间复杂度:递归栈的深度 O(logn)
首先用快慢指针找到中心节点,以中心节点为左链表最后节点、递归左右俩链表,直到链表长度小于等于 1 回溯,
回溯时是将俩有序链表合并成一个有序链表,合并后将头尾嵌回原链表,然后继续回溯
注意:不能以 null 位结尾需要判断 tail 为结尾,最后要将排序好的链表头尾嵌回原链表,注意它是稳定排序处理
特别注意:由于回溯合并链表后,老的 head 位置改变,因此再次回溯决不能使用 head 判断,而是使用 virtual.next 才是正确头结点;当然也可以返回 newHead 节点
代码一:
/*** 链表版二路归并排序(升序,递归版),稳定排序* 时间复杂度为 O(n*logn);空间复杂度:递归栈的深度 O(logn)*/private ListNode solution(ListNode head) {// 判空if (head == null || head.getNext() == null) {return head;}// 添加虚拟节点指向头结点,方便处理ListNode virtual = new ListNode(0, head);// 递归版归并排序核心算法recursionMergeSort(virtual, head, null);return virtual.getNext();}/*** 首先用快慢指针找到中心节点,以中心节点为左链表最后节点、递归左右俩链表,直到链表长度小于等于 1 回溯,* 回溯时是将俩有序链表合并成一个有序链表,合并后将头尾嵌回原链表,然后继续回溯* 注意:不能以 null 位结尾需要判断 tail 为结尾,最后要将排序好的链表头尾嵌回原链表,注意它是稳定排序处理* 特别注意:由于回溯合并链表后,老的 head 位置改变,因此再次回溯决不能使用 head 判断,而是使用 virtual.next 才是正确头结点* @param virtual 当前链表头结点前一个节点* @param head 当前链表头结点* @param tail 当前链表尾结点后一个节点*/private void recursionMergeSort(ListNode virtual, ListNode head, ListNode tail) {// 小于等于 1 个节点回溯,注意结尾为 tailif (head == tail || head.getNext() == tail) {return;}// 快慢指针找到中心节点ListNode mid = getMidNode(virtual, tail);
// System.out.println("head:" + head);
// System.out.println("mid:" + mid);
// System.out.println("tail:" + tail + "\n");// 递归左右俩链表recursionMergeSort(virtual, head, mid.getNext());recursionMergeSort(mid, mid.getNext(), tail);// 左右俩有序链表合并成一个有序链表,返回新的头尾节点
// System.out.println("head:" + head);
// System.out.println("mid:" + mid);
// System.out.println("tail:" + tail + "\n");// 注意不能用使用回溯的 headListNode[] newNodes = mergeTwoSortedLinked(virtual.getNext(), mid.getNext(), tail);ListNode newHead = newNodes[0];ListNode newPreTail = newNodes[1];// 头尾节点嵌回原链表virtual.setNext(newHead);newPreTail.setNext(tail);
// System.out.println("virtual:" + virtual);
// System.out.println("newHead:" + newHead);
// System.out.println("newPreTail:" + newPreTail + "\n");}/*** 左右俩有序链表合并成一个有序链表,返回新的头尾节点* @param lHead 第一个链表头结点* @param rHead 第一个链表尾结点后一个节点,同时也是第二个链表的头结点* @param rTail 第二个链表尾结点后一个节点* @return 新的头尾节点:0-新头结点,1-新尾结点*/private ListNode[] mergeTwoSortedLinked(ListNode lHead, ListNode rHead, ListNode rTail) {ListNode newVirtual = new ListNode();ListNode newPreTail = newVirtual;ListNode l = lHead;ListNode r = rHead;while (l != rHead || r != rTail) {if (l == rHead) {newPreTail.setNext(r);newPreTail = r;r = r.getNext();} else if (r == rTail) {newPreTail.setNext(l);newPreTail = l;l = l.getNext();// 注意稳定排序规则} else if (l.getVal() <= r.getVal()) {newPreTail.setNext(l);newPreTail = l;l = l.getNext();} else {newPreTail.setNext(r);newPreTail = r;r = r.getNext();}}ListNode[] newNodes = new ListNode[2];newNodes[0] = newVirtual.getNext();newNodes[1] = newPreTail;return newNodes;}/*** 快慢指针找到中心节点* @param virtual 头结点前一个节点* @param tail 尾结点后一个节点* @return 中心节点*/private ListNode getMidNode(ListNode virtual, ListNode tail) {ListNode slow = virtual;ListNode fast = virtual;while (fast != tail && fast.getNext() != tail) {slow = slow.getNext();fast = fast.getNext().getNext();}return slow;}
解法二:
链表版二路归并排序(升序,迭代版自底向上),稳定排序
时间复杂度为 O(n*logn);空间复杂度:O(1)
先获取链表长度,然后分割成多组,每组连续俩节点排序,可看做两个有序链表(因为只有一个节点)合并成一个链表,注意最后一组可能不满,
接着连续四个节点排序,同样是两个有序链表合并成一个链表,然后连续八个、十六个…,直到排好序个数大于等于链表长度就完成
注意:链表每次排序后需要嵌回原链表
代码二:
/*** 链表版二路归并排序(升序,迭代版自底向上),稳定排序* 时间复杂度为 O(n*logn);空间复杂度:O(1)*/private ListNode solutionOptimization(ListNode head) {// 判空if (head == null || head.getNext() == null) {return head;}// 迭代版二路归并核心算法return iterationMergeSort(head);}/*** 先获取链表长度,然后分割成多组,每组连续俩节点排序,可看做两个有序链表(因为只有一个节点)合并成一个链表,注意最后一组可能不满,* 接着连续四个节点排序,同样是两个有序链表合并成一个链表,然后连续八个、十六个...,直到排好序个数大于等于链表长度就完成* 注意:链表每次排序后需要嵌回原链表* @return 返回排好序的新的头节点*/private ListNode iterationMergeSort(ListNode head) {// 获取链表长度int len = getLinkedLen(head);System.out.println("len:" + len + "\n");// 头结点前添加虚拟节点,方便操作ListNode virtual = new ListNode(0, head);// 循环操作连续两个节点、四个节点、八个节点...for (int group = 2; group / 2 < len; group *= 2) {// 第一个链表头结点前一个节点ListNode left = virtual;System.out.println("left:" + left);// 每 group 个元素一组,前 group/2 个与后 group/2 个有序链表合并成一个有序链表int halfGroup = group / 2;for (int now = 0; now < len; now += group) {System.out.println(String.format("now:%s group:%s left:%s", now, group, left));// 从第 now 位开始,最多到 len 长度,连续 group 个链表进行合并,然后 left 后移到下一组(每组头结点的前一个节点)left = mergeContinueLinked(group, halfGroup, now, len, left, left.getNext());}System.out.println();}return virtual.getNext();}/*** 获取链表长度*/private int getLinkedLen(ListNode head) {int len = 0;while (head != null) {len++;head = head.getNext();}return len;}/*** 从第 now 位开始,最多到 len 长度,连续 group 个链表进行合并,然后 left 后移* @param group 每组个数* @param halfGroup 半组长度,其为排好序的长度* @param now 当前下标(模拟数组)* @param len 链表总长度* @param preHead 当前链表起点位置的前一个节点* @param lHead 当前链表起点位置* @return lHead 接下来移到的位置的前一个节点*/private ListNode mergeContinueLinked(int group, int halfGroup, int now, int len, ListNode preHead, ListNode lHead) {// 后续不足 halfGroup 个元素,代表均已排if (len <= now + halfGroup) {return null;}// 第一个链表尾结点后一个节点,同时也是第二个链表头结点ListNode rHead = moveBack(lHead, halfGroup);// 第二个链表尾结点后一个节点ListNode rTail = moveBack(rHead, halfGroup);System.out.println(String.format("lHead:%s rHead:%s rTail:%s", lHead, rHead, rTail));// 合并俩有序链表ListNode[] newNodes = mergeTwoSortedLinked2(lHead, rHead, rTail);ListNode newHead = newNodes[0];ListNode newPreTail = newNodes[1];// 合并后的有序链表嵌回原链表preHead.setNext(newHead);newPreTail.setNext(rTail);System.out.println(String.format("preHead:%s newPreTail:%s", preHead, newPreTail) + "\n");return newPreTail;}/*** head 开始后移 halfGroup 个元素,其中移动到 null 则不用再移动了*/private ListNode moveBack(ListNode head, int halfGroup) {while (head != null && halfGroup > 0) {halfGroup--;head = head.getNext();}return head;}/*** 左右俩有序链表合并成一个有序链表,返回新的头尾节点* @param lHead 第一个链表头结点* @param rHead 第一个链表尾结点后一个节点,同时也是第二个链表的头结点* @param rTail 第二个链表尾结点后一个节点* @return 新的头尾节点:0-新头结点,1-新尾结点*/private ListNode[] mergeTwoSortedLinked2(ListNode lHead, ListNode rHead, ListNode rTail) {ListNode newVirtual = new ListNode();ListNode newPreTail = newVirtual;ListNode l = lHead;ListNode r = rHead;while (l != rHead || r != rTail) {if (l == rHead) {newPreTail.setNext(r);newPreTail = r;r = r.getNext();} else if (r == rTail) {newPreTail.setNext(l);newPreTail = l;l = l.getNext();// 保证排序稳定性} else if (l.getVal() <= r.getVal()) {newPreTail.setNext(l);newPreTail = l;l = l.getNext();} else {newPreTail.setNext(r);newPreTail = r;r = r.getNext();}}ListNode[] newNodes = new ListNode[2];newNodes[0] = newVirtual.getNext();newNodes[1] = newPreTail;return newNodes;}
相关文章:

Leetcode 148. 排序链表(二路归并)
题目: 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 解法一: 递归解法,自顶向下 链表版二路归并排序(升序,递归版),稳定排序 时间复杂度…...

记录Paint部分常用的方法
Paint部分常用的方法1、实例化之后Paint的基本配置2、shader 和 ShadowLayer3、pathEffect4、maskFilter5、colorFilter6、xfermode1、实例化之后Paint的基本配置 Paint.Align Align指定drawText如何将其文本相对于[x,y]坐标进行对齐。默认为LEFTPaint.Cap Cap指定了笔画线和路…...

ArrayList集合底层原理
ArrayList集合底层原理ArrayList集合底层原理1.介绍2.底层实现3.构造方法3.1集合的属性4.扩容机制5.其他方法6.总结ArrayList集合底层原理 1.介绍 ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在 内的所有元素。 每个 Array…...

内网部署swagger快解析映射方案发布让外网访问
计算机业内人士对于swagger并不陌生, 不少人选择用swagger做为API接口文档管理。Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法&#x…...

全网最全整理,自动化测试10种场景处理(超详细)解决方案都在这......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 自动化工作流程 自动…...

【c++】指针的学习
指针是C中非常重要的概念,理解指针的使用可以使程序更高效,并且可以处理更加复杂的数据结构。 指针是一个变量,它存储了另一个变量的地址。通过指针访问这个变量可以提高程序的效率,尤其是在处理大型数据结构时。 在C中࿰…...

华为OD机试题,用 Java 解【水仙花数】问题
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…...

【Linux】-- 基本指令
目录 用户管理 adduser passwd userdel pwd ls指令 -l -a -d -F -r -t -R -1 which alias ll ls -n cd cd - cd ~ touch -d stat mkdir -p rmdir rm -r -f man cp 编辑 -r -f mv cat -n tac more less -N head tail | 管道 dat…...

JavaScript 中的 String 类型 模板字面量定义字符串
ECMAScript 6新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串: let str1 早起的年轻人\n喜欢经常跳步;let str2 早起的年轻人喜欢经常跳步;console.log(str1);// 早起的年轻人…...

我国防疫数据报告,2022年广东花费711亿,北京人均支出第一
哈喽大家好,2023年已经过去一段时间了,随着防疫策略的调整,小伙伴们是不是开始到处旅行购物了呢?当然了,对于自身的健康情况小伙伴们还是要多多关注,不要松懈。随着春节过后有序复工复产,各地纷…...

OpenCV-Python学习(22)—— OpenCV 视频读取与保存处理(cv.VideoCapture、cv.VideoWriter)
1. 学习目标 学习 OpenCV 的视频的编码格式 cv.VideoWriter_fourcc;学会使用 OpenCV 的视频读取函数 cv.VideoCapture;学会使用 OpenCV 的视频保存函数 cv.VideoWriter。 2. cv.VideoWriter_fourcc()常见的编码参数 2.1 参数说明 参数说明cv.VideoWr…...

2023-03-05力扣每日一题
链接: https://leetcode.cn/problems/triples-with-bitwise-and-equal-to-zero/ 题意: 模拟一个摩天轮,四个舱,每个舱最多四人,给一个数组,表示摩天轮每切换一次座舱会来多少人排队(人不会走…...

真正的IT技术男是什么样的?
我们经常会听到很多对IT男士的调侃称呼,“屌丝”、“宅男”,会逗的大家捧腹大笑。但是,大家要不要以为称呼IT男是“屌丝”、“宅男”,就当真以为他们是这样了。今天,青鸟学姐就带大家一起来了解一下,真正的…...

在函数中,用指针接收就可以改变相应的内容吗??
作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 我们在不管指针那篇博客,还是在函数那篇博客中,我都给大家讲解过…...

Java+ElasticSearch+Pytorch实现以图搜图
以图搜图,涉及两大功能:1、提取图像特征向量。2、相似向量检索。第一个功能我通过编写pytorch模型并在java端借助djl调用实现,第二个功能通过elasticsearch7.6.2的dense_vector、cosineSimilarity实现。一、准备模型创建demo.py,输…...

【C语言学习笔记】:指针
指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内…...

微信小程序搭建流程
一、申请微信开发者账号虽然开发微信小程序可以使用工具提供的测试号,但是测试号提供的功能极为有限,而且使用测试号开发的微信小程序不能上架发布。因此说我们想要开发一个可以上架的微信小程序,首先必须要申请微信开发者账号。大家尽可放心…...

嵌入式 Linux进程间的通信--信号
目录 信号 信号的概述 信号类型 信号发送 1、kill 函数 2、raise函数 3、pause函数 信号处理 可以结合上一篇文章一起看: 嵌入式 Linux进程之间的通信_丘比特惩罚陆的博客-CSDN博客 信号 信号的概述 软中断信号(signal,又简称为…...

Vue3 核心模块源码解析(中)
【Vue3 核心模块源码解析(上)】讲到了 Vue2 与 Vue3的一些区别,Vue3 新特性的使用,以及略微带了一点源码。那么这篇文章就要从Vue3 模块源码解析 与 Vue3 执行逻辑解析这两个方面去给大家剖析 Vue3 的深层次,一起学习起来吧! 这里…...

华为OD机试题 - 剩余可用字符集(JavaScript)| 含思路
华为OD机试题 最近更新的博客使用说明本篇题解:剩余可用字符集题目输入输出示例一输入输出说明Code解题思路华为OD其它语言版本最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全…...

焦虑的根源
归结起来,焦虑的原因就两条:想同时做很多事,又想立即看到效果。王小波说:人的一切痛苦,本质上都是对自己无能的愤怒。焦虑的本质也契合这一观点:自己的欲望大于能力,又极度缺乏耐心。焦虑就是因为欲望与能力之间差距过大。再往深了…...

1.认识网络爬虫
1.认识网络爬虫网络爬虫爬虫的合法性HTTP协议请求与响应(重点)网络爬虫 爬虫的全名叫网络爬虫,简称爬虫。他还有其他的名字,比如网络机器人,网络蜘蛛等等。爬虫就好像一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达&am…...

【论文速递】WACV 2023 - 一种全卷积Transformer的医学影响分割模型
【论文速递】WACV 2023 - 一种全卷积Transformer的医学影响分割模型 【论文原文】:The Fully Convolutional Transformer for Medical Image Segmentation 【作者信息】:Athanasios Tragakis, Chaitanya Kaul,Roderick Murray-Smith,Dirk Husmeier 论…...

加密图像的脆弱水印及应用
原文题目:《A self-embedding secure fragile watermarking scheme with high quality recovery》 学习笔记: 应用场景 为了确保图像在传输过程中不被损坏,在将原始图像发送到云端之前,将用于篡改检测和恢复的水印嵌入到原始图像…...

python线上商城网站项目前台和后台源码
wx供重浩:创享日记 对话框发送:python51 获取完整源码源文件说明文档配置教程等 1、网站前台 在虚拟环境中启动程序后,使用浏览器访问“http://127.0.0.1:5000”即可进入网站前台首页。如图1所示。 单击首页左上角“注册”按钮,进…...

PowerShell 实现企业微信机器人推送消息
前言企业微信机器人 在ARMS告警管理中创建企业微信机器人后,您可以在通知策略中指定对应的企业微信群用于接收告警。当通知策略的匹配规则被触发时,系统会自动向您指定的企业微信群发送告警通知。企业微信群收到通知后,您可以在企业微信群中…...

IDEA集成Git就是这么简单
IDEA集成Git 文章目录IDEA集成Git配置Git环境配置Git的忽略文件①为什么需要配置忽略文件?②配置忽略文件③引用配置文件配置IDEA初始化项目添加到暂存区方式一:方式二:移除暂存区提交到本地库分支创建分支切换分支版本穿梭配置Git环境 配置…...

springBoot 事务基本原理
springBoot事务基本原理是基于spring的BeanPostProcessor,在springBoot中事务使用方式为: 一、在启动类上添加注解:EnableTransactionManagement 二、在需要事务的接口上添加注解:Transactional 基本原理: 注解&am…...

HBuilderX无线连接真机
说明 安装的是HBuilderX,不是HBuilder,adb.exe所在目录是 x:\HBuilderX\plugins\launcher\tools\adbs\ 里面可能有其他版本,用哪个都,建议使用最新的 配置 首先,将真机使用USB连接到电脑上。 在adb目录中启动命令…...

idea初学笔记
注:初学需安装idea专业版,方便学习使用idea运行内存配置从eclipse工具开发 转 idea工具开发,可设置idea快捷键同eclipse快捷键 file -> Settings -> Keymap -> 选择Eclipse -> OK设置idea项目整体编码格式file -> Settings -> Editor …...