剑指Offer题目笔记23(归并排序)

面试题77:

面试题77

问题:

​ 输入一个链表的头节点,将该链表排序。

解决方案:

​ 使用归并排序。将链表分为两个子链表,在对两个子链表排序后再将它们合并为一个排序的链表。

源代码:
/**
 * 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 sortList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }

        ListNode head1 = head;
        ListNode head2 = split(head);
		
        head1 = sortList(head1);
        head2 = sortList(head2);

        return merge(head1,head2);
    }
	//从链表的中间分割链表并返回切割后的链表头。使用快慢指针,快指针走两步,慢指针走一步,当快指针到达链表尾时,慢指针到达链表中间节点。
    private ListNode split(ListNode head){
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }

        ListNode second = slow.next;
        slow.next = null;

        return second;
    }
	//合并两个子链表
    private ListNode merge(ListNode head1,ListNode head2){
        //创建哨兵节点,用于保存链表头节点
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        while(head1 != null && head2 != null){
            if(head1.val < head2.val){
                cur.next = head1;
                head1 = head1.next;
            }else{
                cur.next = head2;
                head2 = head2.next;
            }

            cur = cur.next;
        }

        cur.next = head1 != null?head1:head2;
        return dummy.next;
    }
}

面试题78:

面试题78

问题:

​ 输入k个排序的链表,将它们合并成一个排序的链表。

第一种方案(最小堆):

解决方案:

​ 使用最小堆。先扫描链表数组将所有排序链表的头节点添加到最小堆,然后将最小堆堆顶的链表节点弹出,因为最小堆堆顶的链表节点是整个堆中链表节点值最小的,弹出后再判断堆顶的链表节点是否存在下一个节点,如果存在就添加到最小堆,如果不存在就不需要添加,以此循环,直到堆中不存在元素。

源代码
/**
 * 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) {
        //创建哨兵节点
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
		//创建最小堆,设置比较规则,链表节点值小的位于堆顶
        PriorityQueue<ListNode> minHeap = new PriorityQueue<>((p1,p2) -> p1.val - p2.val);
        for(ListNode list:lists){
            if(list != null){
                minHeap.offer(list);
            }
        }

        while(!minHeap.isEmpty()){
            ListNode node = minHeap.poll();
            cur.next = node;
            cur = node;

            if(node.next != null){
                minHeap.offer(node.next);
            }
        }

        return dummy.next;
    }
}

第二种方案(归并排序):

解决方案:

​ 输入的k个排序链表可以分为两部分,前k/2个链表和后k/2个链表。如果将前k/2个链表和后k/2个链表分别再分为两个排序链表,再将两个排序链表合并,那么所有链表都合并了。

源代码:
/**
 * 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) {
        if(lists.length == 0){
            return null;
        }

        return mergeLists(lists,0,lists.length);
    }
	
    //将k个排序链表分为前k/2个链表和后k/2个链表
    private ListNode mergeLists(ListNode[] lists,int start,int end){
        if(start + 1 == end){
            return lists[start];
        }

        int mid = (start + end) / 2;
        //前k/2个链表
        ListNode head1 = mergeLists(lists,start,mid);
        //后k/2个链表
        ListNode head2 = mergeLists(lists,mid,end);
		//将两个排序链表合并
        return merge(head1,head2);
    }
	//将两个排序链表合并
    private ListNode merge(ListNode head1,ListNode head2){
        //创建哨兵节点
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
		
        while(head1 != null && head2 != null){
            if(head1.val < head2.val){
                cur.next = head1;
                head1 = head1.next;
            }else{
                cur.next = head2;
                head2 = head2.next;
            }

            cur = cur.next;
        }

        cur.next = head1 != null?head1:head2;
        return dummy.next;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python循环语句for

主要解决什么样的问题&#xff1a;具有重复性、规律性的问题 循环四要素&#xff1a; 循环的开始&#xff08;从第1步开始&#xff1b;从第1步开始/从起点开始&#xff09; 循环的继续条件&#xff08;还没走到第10步&#xff1b;没有碰到墙/就是看距离&#xff09; 循环体&…

算法学习——LeetCode力扣动态规划篇4

算法学习——LeetCode力扣动态规划篇4 377. 组合总和 Ⅳ 377. 组合总和 Ⅳ - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保…

JSQLParserException异常

前言 SQL中加入了租户字段&#xff0c;报这个错&#xff0c;可以查出数据&#xff0c;但是不多&#xff1b;SQL检查无问题 解决 原因一 引入新的SQL解析器检查解析SQL&#xff0c;与mybatis多租户无关 参考 <!--jsqlparser版本太低也无法解析&#xff0c;如2.0--> &…

左侧或水平导航菜单栏与main区域联动

系列文章目录 一、elementui 导航菜单栏和Breadcrumb 面包屑关联 二、左侧导航菜单栏与main区域联动 文章目录 系列文章目录前言一、实现步骤1.<el-menu>中设置属性router为true2.<el-menu-item>中设置路由 route"/"3.<el-main>里设置路由出口4…

Android Studio Iguana | 2023.2.1 补丁 1

Android Studio Iguana | 2023.2.1 Canary 3 已修复的问题Android Gradle 插件 问题 295205663 将 AGP 从 8.0.2 更新到 8.1.0 后&#xff0c;任务“:app:mergeReleaseClasses”执行失败 问题 298008231 [Gradle 8.4][升级] 由于使用 kotlin gradle 插件中已废弃的功能&#…

游戏行业行业竞争越来越激烈,遇到DDoS攻击遭受严重损失该如何解决

近年来&#xff0c;我们见证了数字化的快速发展&#xff0c;随着这样的发展&#xff0c;网络的威胁也逐渐增多&#xff0c;在网络攻击门槛不断降低&#xff0c;行业竞争越来越激烈&#xff0c;游戏行业的DDoS攻击如雨点般密集&#xff0c;在整个DDoS攻击的份额中&#xff0c;游…

C语言goto语句介绍

在C语言中&#xff0c;goto语句是一种流程控制语句&#xff0c;用于无条件地转移到程序中的特定标签位置。尽管goto语句在编程中具有一定的争议&#xff0c;但在某些情况下&#xff0c;它可以提供一种简单有效的解决方案。本文将深入介绍C语言中的goto语句&#xff0c;包括其基…

android安卓英语学习课设

一、关于这个项目ELAPP 该项目是一个基于java开发的服务器-客户端模式的安卓英语学习软件&#xff0c;主要功能点就是背单词&#xff0c;中英文翻译&#xff0c;OCR文字翻译。 服务器端使用springboot&#xff0c;mybatisplus&#xff0c;MySQL&#xff0c;mongodb&#xff0…

Solo 开发者周刊 (第9期):Dawwin首位人工智能编程师或将改变未来?

这里会整合 Solo 社区每周推广内容、产品模块或活动投稿&#xff0c;每周五发布。在这期周刊中&#xff0c;我们将深入探讨开源软件产品的开发旅程&#xff0c;分享来自一线独立开发者的经验和见解。本杂志开源&#xff0c;欢迎投稿。 好文推荐 Dawwin首位人工智能编程师&#…

企业数据被新型.rmallox勒索病毒加密,应该如何还原?

.rmallox勒索病毒为什么难以解密&#xff1f; .rmallox勒索病毒难以解密的主要原因在于其采用了高强度的加密算法&#xff0c;并且这些算法被有效地实施在了病毒程序中。具体来说&#xff0c;.rmallox勒索病毒使用了RSA和AES这两种非常成熟的加密算法。RSA是一种非对称加密算法…

linux安装Tomcat

linux安装Tomcat 下载地址&#xff1a;https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.87/bin/apache-tomcat-8.5.87.tar.gz 将下载的安装包传到该文件夹 解压安装包 tar -zxvf apache-tomcat-8.5.87.tar.gz 配置环境变量 vim /etc/profile 添加指定文件最下方 expo…

【编程笔记】学会使用 Git

目录 一、介绍 Git二、安装 Git三、 常用 linux 目录四、Git 的必要配置(1) 查看和删除之前的配置(2) 配置 Git 五、Git 基本理论六、Git 项目搭建七、Git 文件操作八、分支Git 笔记 ❀❀❀(1) 常规使用(2) 分支 一、介绍 Git &#x1f4d6; VCS&#xff1a;Version Control S…

第六讲 B+树索引

1 B树大家庭 有一种称为 B 树的特定数据结构&#xff0c;人们还使用该术语来泛指一类平衡树数据结构&#xff1a; B-Tree (1971)BTree (1973)B*Tree (1977?)B link-Tree (1981)Bε-Tree (2003)Bw-Tree (2013) 2 B树 BTree 是一种自平衡【self-balance】、有序【ordered】的…

JavaEE 初阶篇-深入了解多线程安全问题(出现线程不安全的原因与解决线程不安全的方法)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 多线程安全问题概述 1.1 线程不安全的实际例子 2.0 出现线程不安全的原因 2.1 线程在系统中是随机调度且抢占式执行的模式 2.2 多个线程同时修改同一个变量 2.3 线…

C语言-编译和链接

目录 1.前言2.编译2.1预处理&#xff08;预编译&#xff09;2.1.1 #define 定义常量2.1.2 #define 定义宏2.1.3带有副作用的宏参数2.1.4宏替换规则2.1.5 #和##2.1.5.1 #运算符2.1.5.2 ## 运算符 2.1.6 命名约定2.1.7 #undef2.1.8 条件编译2.1.9 头文件的包含2.1.9.1 本地文件包…

基于RIP的MGRE综合实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有Ip地址; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b; R2与R5之间使用ppp的cHAP认证&#xff0c;R5为主认证方; R3与R5之间使用H…

Clip算法解读

论文地址&#xff1a;https://arxiv.org/pdf/2103.00020.pdf 代码地址&#xff1a;https://github.com/OpenAI/CLIPz 中文clip代码&#xff1a;https://gitcode.com/OFA-Sys/Chinese-CLIP/overview 一、动机 主要解决的问题&#xff1a; 超大规模的文本集合训练出的 NLP 模…

pbrt-v4 windows编译失败指南

cpu下编译成功很容易&#xff0c;但是gpu有点麻烦&#xff0c;主要有下面几个坑 安装optix 7&#xff0c;cmake build 要加上PBRT_OPTIX_PATH cmake cuda 版本要对应&#xff0c;不然会出现 cuda not found&#xff0c;或者generate的时候报错&#xff0c;导致最后pbrt.exe --…

FANUC机器人故障诊断—报警代码更新(三)

FANUC机器人故障诊断中&#xff0c;有些报警代码&#xff0c;继续更新如下。 一、报警代码&#xff08;SRVO-348&#xff09; SRVO-348DCS MCC关闭报警a&#xff0c;b [原因]向电磁接触器发出了关闭指令&#xff0c;而电磁接触器尚未关闭。 [对策] 1.当急停单元上连接了CRMA…