手撕小顶堆

1. 抛砖引玉

在这里插入图片描述

给定两个以升序排列的整数数组 nums1 和 nums2 , 以及一个整数 k 。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。
请找到和最小的 k 个数对 (u1,v1), (u2,v2) … (uk,vk) 。

分析

大根堆(大顶堆):大根堆即指在逻辑上的二叉树结构中,根结点>子结点,总是最大的,并且在堆的每一个局部都是这样。

小根堆(小顶堆):与大根堆相反,即所有局部的根都小于子节点。
在这里插入图片描述
在java中优先队列是使用堆实现的。
主要有两个类

  1. PriorityQueue 线程不安全
  2. PriorityBlockingQueue 线程安全

我这里使用PriorityQueue,这一题我们可以通过一个大顶堆来维护一个答案序列

Jdk优先队列允许我们自定义比较器,可以比较的对象是可以使用优先队列的比较条件

PriorityQueue默认实现的是小顶堆,这里我们实现一个大顶堆

                PriorityQueue<List<Integer>> queue = new PriorityQueue<List<Integer>>(new Comparator<List<Integer>>() {public int compare(List<Integer> m, List<Integer> n) {if(m.get(0) + m.get(1) < n.get(0) + n.get(1)){return 1;}else{return -1;}}});

到这里,我们可以进行两次for循环

class Solution {public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {List<List<Integer>>result = new ArrayList<>();//构造有些队列,自定义比较器PriorityQueue<List<Integer>> queue = new PriorityQueue<List<Integer>>(new Comparator<List<Integer>>() {public int compare(List<Integer> m, List<Integer> n) {if(m.get(0) + m.get(1) < n.get(0) + n.get(1)){return 1;}else{return -1;}}});//两次for循环,向优先队列中添加值for(int i = 0; i < nums1.length; i++){for(int j = 0; j < nums2.length; j++){if(queue.size() < k){queue.offer(Arrays.asList(nums1[i],nums2[j]));}else{if(nums1[i] + nums2[j] < queue.peek().get(0) + queue.peek().get(1)){queue.poll();queue.offer(Arrays.asList(nums1[i],nums2[j]));}else{if(nums1[i] > queue.peek().get(0) && nums2[j] > queue.peek().get(1)){break;}}}}}for(List<Integer>list : queue){result.add(list);}return result;}
}

可能有人要问了,两次for循环为什么我不直接暴力遍历

因为:我们维护了一个答案序列,知道最大或最小值,我们可以轻松淘汰一些无效不必要的遍历,例如:

当的数组1新的值和数组2新的值大于维护的答案队列中堆顶最大的值的时候,这次遍历就是不必要的,可以结束本次小循环。

if(nums1[i] > queue.peek().get(0) && nums2[j] > queue.peek().get(1)){break;}

2. 手撕堆排序

如果是当初,可能只会用 api 就够了,但是现如今,手撕堆排序也是不可或缺的技能了。

  1. 选择数据结构
    堆排序的最佳选项自然是数组,但是数组用起来并不好用,并不能动态扩容,我们这里使用同样底层是数据的数据结构 ArrayList
class Heap{int cap = 10;public Heap(int cap) {this.cap = cap;}ArrayList<Integer>list = new ArrayList<>();public void insert(int num){}public int peek(){return list.get(0);}private void bottomSort(int i){}private void topSort(int i){}}
  1. 实现的函数

对外的函数主要有插入方法和返回堆顶堆方法,对内主要是两个排序方法,是上浮和下浮方法。

为什么有上浮和下浮两个方法?
我刚开始的时候只写了下浮方法,因为 前 k 大的算法题已经深深刻入我的脑海,但是随即就想到了一个问题,没加满的时候如何放置?

由于数组内的顺序很重要,不能随便移动,加入头部自然不可能,只能放到尾部,然后进行判值上浮,所以不得不同时实现两个方法,在数据不满的时候使用上浮方法,满了之后替换首个字符,使用下浮方法。

这里我实现小顶堆的方法,希望通用型更强的朋友可以试着使用关键字实现小顶堆和大顶堆两用的方法。

  1. 上浮方法
private void bottomSort(int i){while (i > 0){int iV = list.get(i);int lastIndex= (i - 1) / 2;int lastV = list.get(lastIndex);if(iV < lastV){list.set(i,lastV);list.set(lastIndex,iV);}i = lastIndex;}}

上浮方法比较简单,往往只用和父节点比较就可以,条件终止条件就是,i 已经交换到 0,即头节点。

  1. 下浮方法
private void topSort(int i){int cur = i;int iV = list.get(i);while (true){int left = 2 * i + 1;int right = 2 * i + 2;if(left < list.size() && list.get(cur) > list.get(left)){cur = left;}if(right < list.size() && list.get(cur) > list.get(right)){cur = right;}if(cur == i){break;}else {list.set(cur,iV);}}}

这里我们用了一个很巧妙的方法把大的数据下浮到较小的叶子上叶子上,实际上堆并没有如此严格,只保证相对有序就可以

插入方法和堆顶方法

 public void insert(int num){int size = list.size();if(cap == size){if(num <= peek()){return;}list.set(0,num);topSort(0);}else {list.add(num);bottomSort(size);}}public int peek(){return list.get(0);}

两个方法相对简单,就不多阐述了

3. 整体小顶堆代码

package 堆排序;import java.util.ArrayList;public class Solution {public static void main(String[] args) {Heap heap = new Heap(10);heap.insert(100);heap.insert(20);heap.insert(221);heap.insert(232);heap.insert(234);heap.insert(22);heap.insert(21);heap.insert(20);heap.insert(19);heap.insert(18);heap.insert(17);System.out.println(heap.peek());}}
class Heap{int cap = 10;public Heap(int cap) {this.cap = cap;}ArrayList<Integer>list = new ArrayList<>();public void insert(int num){int size = list.size();if(cap == size){if(num <= peek()){return;}list.set(0,num);topSort(0);}else {list.add(num);bottomSort(size);}}public int peek(){return list.get(0);}private void bottomSort(int i){while (i > 0){int iV = list.get(i);int lastIndex= (i - 1) / 2;int lastV = list.get(lastIndex);if(iV < lastV){list.set(i,lastV);list.set(lastIndex,iV);}i = lastIndex;}}private void topSort(int i){int cur = i;int iV = list.get(i);while (true){int left = 2 * i + 1;int right = 2 * i + 2;if(left < list.size() && list.get(cur) > list.get(left)){cur = left;}if(right < list.size() && list.get(cur) > list.get(right)){cur = right;}if(cur == i){break;}else {list.set(cur,iV);}}}}

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

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

相关文章

多旋翼无人机维修、组装、调试技术详解

多旋翼无人机作为现代航拍、农业植保、物流运输等领域的重要工具&#xff0c;其性能的稳定性和操作的便捷性对于任务的完成至关重要。因此&#xff0c;掌握多旋翼无人机的维修、组装与调试技术&#xff0c;对于无人机操作员及维修人员来说至关重要。本文将详细介绍这三个方面的…

线程池ForkJoinPool实战及其工作原理分析

1. 由一道算法题引发的思考 算法题&#xff1a;如何充分利用多核CPU的性能&#xff0c;快速对一个2千万大小的数组进行排序&#xff1f; 这道算法题可以拆解来看&#xff1a; 1&#xff09;首先这是一道排序的算法题&#xff0c;而且是需要使用高效的排序算法对2千万大小的数…

从一个文本文件中挑选出符合条件的内容行

某天&#xff0c;张三得到一个需求&#xff0c;将如下格式的文本文件中的文件名开头的内容行提取出来&#xff0c;存入一个新的文本文件。 ok 0 文件名&#xff1a;1_zoukaige.mp3 index:10 文件名&#xff1a;2_dahan.mp3 index:20 文件名&#xff1a;3_kuai.mp3 index:30 文件…

【JavaEE精炼宝库】HTTP | HTTPS 协议详解

文章目录 一、HTTP 简介二、HTTP 协议格式&#xff1a;2.1 抓包工具的使用&#xff1a;2.2 HTTP 请求报文格式&#xff1a;2.3 HTTP 响应报文格式&#xff1a;2.4 HTTP 协议格式总结&#xff1a; 三、HTTP 请求详解&#xff1a;3.1 刨析 URL&#xff1a;3.2 方法(method)&#…

Kerberos自我总结Kerberos自我总结

1、协议原理与漏洞产生 1.1 kerberos Kerberos协议是一种基于票据Ticket的认证方式&#xff0c;它由三个角色组成&#xff0c;分别是客户端Client、服务端Server和秘钥分发中心KDC。 协议中的交互分为六步&#xff0c;为AS_REQ、AS_REP、TGS_REQ、TGS_REP、AP_REQ和AP_REP …

揭露大模型本质,大模型入门必看的12本书!看完我直接跪了

敢不敢用一年时间读完这12本书&#xff0c;模型入门必看的12本书&#xff01;建议收藏&#xff01;&#xff01; 第一本&#xff1a; 《基于GPT-3,ChatGPT,GPT-4等Transformer架构的自然语言处理》 主要内容 了解用于解决复杂语言问题的新技术。将GPT-3与T5、GPT-2和基于BE…

用Python实现时间序列模型实战——Day 28-29: 项目报告与展示

一、学习内容 1.1 项目报告的撰写与优化 项目报告应该从项目背景、数据探索、建模过程、预测结果、模型评估等方面进行全面描述。通过清晰的图表、简明的文字和合理的模型选择来优化报告的表达。 1.2 项目结果的展示与交流 通过展示图表、代码、关键模型的结果&#xff0c;…

Linux系统中的进程调度队列

目录 一、进程调度队列结构 二、活动队列与过期队列 1.queue[140] 2.bitmap[5] 一、进程调度队列结构 Linux系统中&#xff0c;每一个CPU都有一个进程调度队列runqueue&#xff0c;如图所示 二、活动队列与过期队列 运行队列runqueue中有两个指针*active、*expired。*acti…

从小白到大神:C语言预处理与编译环境的完美指南(下)

从小白到大神&#xff1a;C语言预处理与编译环境的完美指南&#xff08;上&#xff09;-CSDN博客 &#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;上篇链接在这~~&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x…

角色权限管理实现学习

逻辑&#xff1a; 权限表(Sys_Power):存所需授权才能访问的检验字段 授权表/角色权限表(Sys_RolePower):存角色所能访问的权限字段 角色表(Sys_Role)&#xff1a;定义角色(管理员&#xff0c;部门负责人&#xff0c;项目负责人...) 用唯一的权限字段标注所要授权才能访问的…

心理辅导系统设计与Spring Boot技术

5 系统的实现 5.1学生功能模块的实现 学生进入本系统可查看系统信息&#xff0c;系统主界面展示如图5-1所示。 图5-1系统主界面图 5.1.1 学生登录界面 学生在登录时需输入正确的登录用户名和密码&#xff0c;系统会以登录用户名、密码为参数进行登录信息的验证&#xff0c;信…

Keil MDK5学习记录

2024.9.19 1. no browse information available in ‘xxx’的问题 成功解决Keil MDK5中no browse information available in ‘xxx’的问题-CSDN博客https://blog.csdn.net/bean_business/article/details/1091894452. .c文件中显示函数列表 如何在Keil5里.c文件中显示函数列表…

oracle数据库启动

文章目录 背景一、步骤1.登录oracle用户2.启动监听服务3.启动数据库 背景 oracle数据库启动 一、步骤 1.登录oracle用户 代码如下&#xff08;示例&#xff09;&#xff1a; su - oracle2.启动监听服务 代码如下&#xff08;示例&#xff09;&#xff1a; lsnrctl start成…

AI音乐创作带给音乐原创人的挑战和机遇

随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;AI音乐创作在全球音乐产业中逐渐崭露头角。人工智能不仅能生成旋律、和声&#xff0c;甚至可以模仿艺术家风格创作出接近真实人类创作的作品。这一技术的崛起给音乐原创人带来了前所未有的挑战&#xff0c;但…

【PyQt5】QWidget子类所有子类

QWidget子类 [QObject 学习](https://editor.csdn.net/md/?articleId142371795) 2024-09-19更新QWidget子类所有子类 2024-09-17发布子类QAbstractButton类 2024-09-17正在学习中QAbstractslider类QAbstractSpinBox类QFrame类QCalendarwidget类QComboBox类QDialogButtonBox类Q…

【计算机网络 - 基础问题】每日 3 题(十八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

uniapp 微信小程序 订阅消息功能实现

该网址 https://api.weixin.qq.com 上线后不可访问&#xff0c;调用该网址操作需在后端&#xff08; 重要&#xff01; 重要&#xff01; 重要&#xff01;&#xff09; 1.首先拿到的三个码 //微信公众平台 //https://mp.weixin.qq.com const wxappid "管理-开发管理-A…

QTCreator 调试:unknown debugger type “No engine“

QTCreator 调试&#xff1a;unknown debugger type "No engine" - kaizenly - 博客园 (cnblogs.com) 一开始Debuggers---Auto-detected这里第一row第一个项是标红的&#xff0c;然后没改东西&#xff0c;点完应用Apply以后&#xff0c;就可以调试了...&#xff08;不…

Spring Boot助力高校心理辅导系统升级

3 系统分析 3.1可行性分析 在进行可行性分析时&#xff0c;我们通常根据软件工程里方法&#xff0c;通过四个方面来进行分析&#xff0c;分别是技术、经济、操作和法律可行性。因此&#xff0c;在基于对目标系统的基本调查和研究后&#xff0c;对提出的基本方案进行可行性分析。…

【华为杯】2024华为杯数模研赛E题 解题思路

题目 高速公路应急车道紧急启用模型 问题背景 高速公路拥堵现象的原因众多&#xff0c;除了交通事故外&#xff0c;最典型的就是部分路段出现瓶颈现象&#xff0c;主要原因是车辆汇聚&#xff0c;而拥堵后又容易蔓延。高速公路一些特定的路段容易形成堵点&#xff0c;如匝道…