认识O(NlogN)的排序
归并排序
归并排序(任何一个递归)如果不懂可以画一个树状结构去帮助自己去理解。
核心排序方法为Merger
public class 归并排序 {public static void main(String[] args) {int[] arr1 = {3, 1, 2, 2, 5, 6};int[] arr2 = Arrays.copyOf(arr1, arr1.length);process(arr1, 0, arr1.length - 1);sort(arr2);}/*** 归并排序* 1.将左边排好序,再将右边排好序* 2.对比左右两个区间再进行排序* 递归过程,当 L==R 时停止,也就是当数组被二分为只有一个数时停止,* 这时他的上层只有两个数,调用merger进行排序*/public static void process(int[] arr, int L, int R) {if (L == R) {return;}//获取中点位置,为避免整数溢出现象而不写为(R + L) / 2,//原因是如果R与L都是int边缘,相加将越界int mid = L + ((R - L) >> 1);//左区域排序process(arr, L, mid);//右区域排序process(arr, mid + 1, R);//对比左右两个区间再进行排序merger(arr, L, mid, R);//打印print(arr, "arr1");}/*** 两个指针,一个指向L(最左索引),一个指向R(最右索引)* 如果L,R都不越界,对比L,R大小将排好序的数据放入新数组* 如果其中一个越界,将未越界数组剩余数据放入新数组的后面*/private static void merger(int[] arr, int L, int mid, int R) {int[] help = new int[R - L + 1];//记录新数组排序到的位置int i = 0;int p1 = L;int p2 = mid + 1;while (p1 <= mid && p2 <= R) {help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];}//如果右边越界,左边剩余数据会全部填充到新数组后边while (p1 <= mid) {help[i++] = arr[p1++];}while (p2 <= R) {help[i++] = arr[p2++];}for (i = 0; i < help.length; i++) {arr[L + i] = help[i];}}public static void sort(int[] arr) {Arrays.sort(arr);print(arr, "arr2");}public static void print(int[] arr, String a) {StringBuilder sb = new StringBuilder();sb.append(a + "= {");for (int i = 0; i < arr.length; i++) {if (i > 0) {sb.append(", ");}sb.append(arr[i]);}sb.append("}");System.out.println(sb.toString());}
}
小和问题/逆序对问题(归并排序变种)
小和问题:在一个数组中,每一个数左边比当前数小的数累加起来,叫做数据的小和。
例:数组{1,3,4,2,5} 1的小和为0 、3的小和为 1、4的小和为1+3 = 4、2的小和为 1、5的小和为1+3+4+2 = 10。
逆序对问题:在一个数组中,左边的数如果比右边的数大,则两个数构成一个逆序对,请计算出逆序对的数量。
思考逻辑
正常思维(暴力解法):小和问题,需要向左寻找比自己小的数,例如:3向前寻找1,4向前寻找1,3。如果是这种情况下数组左边的数每次都需要被遍历一次,没有重复利用其之前搜寻到的数据。
逆向思考:小和问题,正常向左寻找比自己小的数,边为向右寻找比自己大的数。也就是1右边有4个数比自己大,就是4个1、3右边有2个数比自己大,就是2个3、4右边有一个数比自己大,就是一个4、2右边有一个数比自己大也就是一个2.共计16.
在上述过程中我们发现1考虑过之后后面数就无需考虑了,也就是利用到之前的信息了。
小和问题/逆序对问题的关键就是找到逆向思路,根据其能够重复利用信息的特点就可以考虑归并排序。
public class 小和问题/逆序对问题 {public static void main(String[] args) {int[] arr = {3, 2, 4, 5, 0};int[] testArr = Arrays.copyOf(arr, arr.length);int nums = process(testArr, 0, testArr.length - 1);System.out.println(nums);}public static int process(int[] arr, int L, int R) {if (L == R) {return 0;}int mid = L + ((R - L) >> 1);//需要左右两边统计和合并统计return process(arr, L, mid)+ process(arr, mid + 1, R)+ merger(arr, L, mid, R);}private static int merger(int[] arr, int L, int mid, int R) {int[] help = new int[R - L + 1];int i = 0;int p1 = L;int p2 = mid + 1;int res = 0;while (p1 <= mid && p2 <= R) {//逆序对问题可以转变为,找出左边比当前数大的个数res += arr[p1] > arr[p2] ? mid - p1+1 : 0;//逆序对问题//res += arr[p1] <= arr[p2] ? (R-p2+1)*arr[p1] : 0; 小和问题//按照顺序排序是必须的,这样就可以根据第一个位置的大小快速确认后续数据是否需要统计//后续数据就可以根据索引进行计算help[i++] = arr[p2] >= arr[p1] ? arr[p1++] : arr[p2++];}while (p1 <= mid) {help[i++] = arr[p1++];}while (p2 <= R) {help[i++] = arr[p2++];}for (i = 0; i < help.length; i++) {arr[L+i] = help[i];}return res;}
}
快排
荷兰旗问题
给定一个数num,要求将数组划分为三部分,一部分是小于num,一部分是等于num,一部分是大于num。
三指针解法:
当前数称为current,如果current < num,指针1的前一个位置与arr[i]交换位置,指针1向右移动(为什么要交换?因为当current = num时 指针3要向前移动)
如果current = num,那么指针3++
如果current > num,指针2向左移动一个位置,指针2的前一个位置与与i交换位置
指针1划分小于区域,指针2划分大于区域,指针1、2共同划分出来等于区域。指针3的作用是找出等于num的数并跳过,并且指针1、2的交换对象都是指针2.(先交换再移动。写代码的时候要知道指针该怎么移动,这是写代码的重点)
public class 荷兰旗问题 {public static void main(String[] args) {int[] arr = {3,2,5,4,4,0,1,9};int[] copy = Arrays.copyOf(arr, arr.length);sort(copy,4);for (int i : copy) {System.out.print(i+" ");}}public static void sort(int[] arr, int num) {int less = -1;int greate = arr.length;int index = 0;while(index < greate){if (arr[index] < num) {swap(arr, ++less, index++);}else if(arr[index] == num){index++;}else {swap(arr, index, --greate);}}}// 交换数组中两个元素的位置public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}
快排实现
快排就是在荷兰旗问题上添加排序过程。怎么理解那,荷兰旗问题划分为大于、小于、等于三个区间,数如果处于等于的位置那么这个数在整个有序集合的位置就不会变,利用递归就可以划分出无数个小区间,小区间到只有一个数的时候,那么整个大区间就都有序了
public class 快排 {public static void main(String[] args) {int[] arr = {3,2,5,4,4,0,1,9};int[] copy = Arrays.copyOf(arr, arr.length);quickSort(copy,0,copy.length-1);for (int i : copy) {System.out.print(i+" ");}}public static void quickSort(int[] arr, int L, int R) {if (L < R) {//swap在这里随机抽取目标数放入R位置swap(arr, L + (int) (Math.random()) * (R - L + 1), R);//分区,需要返回下一次递归划分的区间int[] partition = partition(arr, L, R);quickSort(arr,L,partition[0]);//需要+1的原因是右区间右交换了一个原先在末尾位置的目标数quickSort(arr,partition[1]+1,R);}}/**** @param L L代表着遍历的索引位置* 就是荷兰旗问题中的index,这里可以直接使用L代替* @param R 代表目标数* 因为随机抽取的目标数会换到最后一个位置,可以使用R代替*/public static int[] partition(int[] arr, int L, int R) {int less = L - 1;int more = R;while (L < more) {if (arr[L] < arr[R]) {swap(arr, ++less, L++);} else if (arr[L] == arr[R]) {L++;} else if (arr[L] > arr[R]) {swap(arr, L, --more);}}//将目标数重新交换到等于区间内swap(arr, more, R);//返回的数组表示,大于区间与小于区间的边界,目的是为下一次递归提供划分区间信息return new int[]{less, more};}public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}
。
核心问题,区间如何划分,也就是如何选出一个目标数。单纯用数组最后一个数作为目标数也可以,但是这样如果遇到{1,2,3,4,5,6,7,8,9}这种顺序的集合那么他的时间复杂度就为O(n^2)。所以为了避免这种情况的发生,目标数在区间内随机抽取,如果是随机抽取的情况下根据数学期望那么时间复杂度就为O(NLogN)
相关文章:

认识O(NlogN)的排序
归并排序 归并排序(任何一个递归)如果不懂可以画一个树状结构去帮助自己去理解。 核心排序方法为Merger public class 归并排序 {public static void main(String[] args) {int[] arr1 {3, 1, 2, 2, 5, 6};int[] arr2 Arrays.copyOf(arr1, arr1.len…...

[手机Linux] onepluse6T 系统重新分区
一,刷入TWRP 1. 电脑下载 Fastboot 工具(解压备用)和对应机型 TWRP(.img 后缀文件,将其放入前面解压的文件夹里) 或者直接这里下载:TWRP 2. 将手机关机,长按音量上和下键 开机键 进入 fastbo…...

对ReentrantLock的公平性进行测试
ReentrantLock公平性实现原理 在ReentrantLock类内部定义了一个内部类Sync以及两个实现NonfairSync和FairSync,它们内部定义了锁获取和释放的逻辑,下面我列出了两种同步类的代码,通过观察两个代码的差异就可以看到公平性是如何实现的。 Nonf…...

LabVIEW之TDMS文件
在很多场合,早期的LabVIEW版本不得不借助常规的数据库来做一些数据管理工作,但常规数据库对于中高速数据采集显然是不合适的,因为高速数据采集的数据量非常大,用一般的数据库无法满足存储数据的要求。 直到TDM(Technical Data Ma…...

DeepSeek 实现原理探析
DeepSeek 实现原理探析 引言 DeepSeek 是一种基于深度学习的智能搜索技术,它通过结合自然语言处理(NLP)、信息检索(IR)和机器学习(ML)等多领域的技术,旨在提供更加精准、智能的搜索…...

2021 年 9 月青少年软编等考 C 语言五级真题解析
目录 T1. 问题求解思路分析T2. 抓牛思路分析T3. 交易市场思路分析T4. 泳池思路分析T1. 问题求解 给定一个正整数 N N N,求最小的 M M M 满足比 N N N 大且 M M M 与 N N N 的二进制表示中有相同数目的 1 1 1。 举个例子,假如给定 N N N 为 78 78 78,二进制表示为 …...
洛谷网站: P3029 [USACO11NOV] Cow Lineup S 题解
题目传送门: P3029 [USACO11NOV] Cow Lineup S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 前言: 这道题的核心问题是在一条直线上分布着不同品种的牛,要找出一个连续区间,使得这个区间内包含所有不同品种的牛,…...

编程领域的IO模型(BIO,NIO,AIO)
目前对于市面上绝大多数的应用来说,不能实现的业务功能太少了。更多的是对底层细节,性能优化的追求。其中IO就是性能优化中很重要的一环。Redis快,mysql缓冲区存在的意义。都跟IO有着密切关系。IO其实我们都在用,输入输出流这块。…...

DeepSeek和ChatGPT的对比
最近DeepSeek大放异彩,两者之间有什么差异呢?根据了解到的信息,简单做了一个对比。 DeepSeek 和 ChatGPT 是两种不同的自然语言处理(NLP)模型架构,尽管它们都基于 Transformer 架构,但在设计目标…...

Pyqt 的QTableWidget组件
QTableWidget 是 PyQt6 中的一个表格控件,用于显示和编辑二维表格数据。它继承自 QTableView,提供了更简单的方式来处理表格数据,适合用于需要展示结构化数据的场景。 1. 常用方法 1.1 构造函数 QTableWidget(parent: QWidget None)&#x…...

4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践
相比传统的单体应用,微服务架构通过将大型系统拆分成多个独立的小服务,不仅提升了系统的灵活性和扩展性,也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践,从而构建一个稳定、高效、易维…...

网络安全威胁框架与入侵分析模型概述
引言 “网络安全攻防的本质是人与人之间的对抗,每一次入侵背后都有一个实体(个人或组织)”。这一经典观点概括了网络攻防的深层本质。无论是APT(高级持续性威胁)攻击、零日漏洞利用,还是简单的钓鱼攻击&am…...

树和二叉树_7
树和二叉树_7 一、leetcode-102二、题解1.引库2.代码 一、leetcode-102 二叉树的层序遍历 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 样例输入:root [3,9,20,null,nu…...

不同标签页、iframe或者worker之间的广播通信——BroadcastChannel
BroadcastChannel是一个现代浏览器提供的 API,用于在同一浏览器的不同浏览上下文(如不同的标签页、iframe 或者 worker)之间进行消息传递。它允许你创建一个广播频道,通过该频道可以在不同的浏览上下文之间发送和接收消息。 Broa…...

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具
开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具 背景与研究目的 在快速发展的软件开发领域,代码辅助工具已成为提高开发效率和质量的关键。然而,商业付费工具如通义灵码和腾讯AI代码助手,尽管功能强大,但其高昂的成本和许可证限制,使得许多企业寻求更具吸…...

AUTOSAR汽车电子嵌入式编程精讲300篇-基于FPGA的CAN FD汽车总线数据交互系统设计
目录 前言 汽车总线以及发展趋势 汽车总线技术 汽车总线发展趋势 CAN FD总线国内外研究现状 2 系统方案及CAN FD协议分析 2.1系统控制方案设计 2.2 CAN FD总线帧结构分析 2.2.1数据帧分析 2.2.2远程帧分析 2.2.3过载帧分析 2.2.4错误帧分析 2.2.5帧间隔分析 2.3位…...

STC51案例操作
案例 1:LED 闪烁 功能描述:通过操作 P1 口寄存器,让连接在 P1.0 引脚的 LED 以一定间隔闪烁。 #include <reg51.h>// 延时函数 void delay(unsigned int time) {unsigned int i, j;for (i 0; i < time; i)for (j 0; j < 123; …...

多光谱技术在华为手机上的应用发展历史
2018 年,华为 P20 系列首次搭载 5 通道色温传感器,可帮助手机在不同光照条件下保持画面色彩一致性。 2020 年,华为 P40 系列搭载 8 通道多光谱色温传感器(实际为 11 通道,当时只用 8 个通道检测可见光)&am…...

C语言:函数栈帧的创建和销毁
目录 1.什么是函数栈帧2.理解函数栈帧能解决什么问题3.函数栈帧的创建和销毁的过程解析3.1 什么是栈3.2 认识相关寄存器和汇编指令3.3 解析函数栈帧的创建和销毁过程3.3.1 准备环境3.3.2 函数的调用堆栈3.3.3 转到反汇编3.3.4 函数栈帧的创建和销毁 1.什么是函数栈帧 在写C语言…...

NLP_[2]_文本预处理-文本数据分析
文章目录 4 文本数据分析1 文件数据分析介绍2 数据集说明3 获取标签数量分布4 获取句子长度分布5 获取正负样本长度散点分布6 获取不同词汇总数统计7 获取训练集高频形容词词云8 小结 4 文本数据分析 学习目标 了解文本数据分析的作用.掌握常用的几种文本数据分析方法. 1 文…...

【工具篇】深度揭秘 Midjourney:开启 AI 图像创作新时代
家人们,今天咱必须好好唠唠 Midjourney 这个在 AI 图像生成领域超火的工具!现在 AI 技术发展得那叫一个快,各种工具层出不穷,Midjourney 绝对是其中的明星产品。不管你是专业的设计师、插画师,还是像咱这种对艺术创作有点小兴趣的小白,Midjourney 都能给你带来超多惊喜,…...

从O(k*n)到O(1):如何用哈希表终结多层if判断的性能困局
【前言】 本文将以哈希表重构实战为核心,完整展示如何将传统条件匹配逻辑(上千层if-else判断)转化为O(1)的哈希表高效实现。通过指纹验证场景的代码级解剖,您将深入理解: 1.哈希函数设计如何规避冲突陷阱 2.链式寻址法的工程实现…...

视频采集卡接口
采集卡的正面有MIC IN、LINE IN以及AUDIO OUT三个接口, MIC IN为麦克风输入,我们如果要给采集到的视频实时配音或者是在直播的时候进行讲解,就可以在这里插入一个麦克风, LINE IN为音频线路输入,可以外接播放背景音乐…...

蓝桥杯真题 - 像素放置 - 题解
题目链接:https://www.lanqiao.cn/problems/3508/learning/ 个人评价:难度 3 星(满星:5) 前置知识:深度优先搜索 整体思路 深搜,在搜索过程中进行剪枝,剪枝有以下限制条件…...

vue基础(三)
常用指令 1. v-bind 固定绑定与动态绑定: 语法: 标准语法:v-bind:属性"动态数据" 简写语法::属性"动态数拓" <!DOCTYPE html> <html lang"en"><head><me…...

使用Python开发PPTX压缩工具
引言 在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,不便于传输和存储。为了应对这一问题,我们可以使用Python的wxPython图形界面库结合python-pptx和Pillow,开发一个简单的PPTX压缩工具。本文将详细介绍如何实现这一…...

ubuntu24.04安装布置ros
最近换电脑布置机器人环境,下了24.04,但是网上的都不太合适,于是自己试着布置好了,留作有需要的人一起看看。 文章目录 目录 前言 一、确认 ROS 发行版名称 二、检查你的 Ubuntu 版本 三、安装正确的 ROS 发行版 四、对于Ubuntu24…...

SQL 秒变 ER 图 sql转er图
🚀SQL 秒变 ER 图,校园小助手神了! 学数据库的宝子们集合🙋♀️ 是不是每次碰到 SQL 转 ER 图就头皮发麻?看着密密麻麻的代码,脑子直接死机,好不容易理清一点头绪,又被复杂的表关…...

【AI知识点】如何判断数据集是否噪声过大?
【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】【读书与思考】【AI应用】 判断数据集是否 噪声过大 是数据分析和机器学习建模过程中至关重要的一步。噪声数据会导致模型难以学习数据的真实模式,从而影响预测效果。以下是一些常见的方法来判断数据…...

网络安全治理架构图 网络安全管理架构
网站安全攻防战 XSS攻击 防御手段: - 消毒。 因为恶意脚本中有一些特殊字符,可以通过转义的方式来进行防范 - HttpOnly 对cookie添加httpOnly属性则脚本不能修改cookie。就能防止恶意脚本篡改cookie 注入攻击 SQL注入攻击需要攻击者对数据库结构有所…...