当前位置: 首页 > news >正文

认识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)的排序

归并排序 归并排序&#xff08;任何一个递归&#xff09;如果不懂可以画一个树状结构去帮助自己去理解。 核心排序方法为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 系统重新分区

一&#xff0c;刷入TWRP 1. 电脑下载 Fastboot 工具&#xff08;解压备用&#xff09;和对应机型 TWRP&#xff08;.img 后缀文件&#xff0c;将其放入前面解压的文件夹里&#xff09; 或者直接这里下载:TWRP 2. 将手机关机&#xff0c;长按音量上和下键 开机键 进入 fastbo…...

对ReentrantLock的公平性进行测试

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

LabVIEW之TDMS文件

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

DeepSeek 实现原理探析

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

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 题解

题目传送门&#xff1a; P3029 [USACO11NOV] Cow Lineup S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 前言&#xff1a; 这道题的核心问题是在一条直线上分布着不同品种的牛&#xff0c;要找出一个连续区间&#xff0c;使得这个区间内包含所有不同品种的牛&#xff0c;…...

编程领域的IO模型(BIO,NIO,AIO)

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

DeepSeek和ChatGPT的对比

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

Pyqt 的QTableWidget组件

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

4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践

相比传统的单体应用&#xff0c;微服务架构通过将大型系统拆分成多个独立的小服务&#xff0c;不仅提升了系统的灵活性和扩展性&#xff0c;也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践&#xff0c;从而构建一个稳定、高效、易维…...

网络安全威胁框架与入侵分析模型概述

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

树和二叉树_7

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

不同标签页、iframe或者worker之间的广播通信——BroadcastChannel

BroadcastChannel是一个现代浏览器提供的 API&#xff0c;用于在同一浏览器的不同浏览上下文&#xff08;如不同的标签页、iframe 或者 worker&#xff09;之间进行消息传递。它允许你创建一个广播频道&#xff0c;通过该频道可以在不同的浏览上下文之间发送和接收消息。 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&#xff1a;LED 闪烁 功能描述&#xff1a;通过操作 P1 口寄存器&#xff0c;让连接在 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 年&#xff0c;华为 P20 系列首次搭载 5 通道色温传感器&#xff0c;可帮助手机在不同光照条件下保持画面色彩一致性。 2020 年&#xff0c;华为 P40 系列搭载 8 通道多光谱色温传感器&#xff08;实际为 11 通道&#xff0c;当时只用 8 个通道检测可见光&#xff09;&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 文…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

表单设计器拖拽对象时添加属性

背景&#xff1a;因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...