认识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)

        

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用Gemini模型,国内如何订阅购买Gemini Pro的教程,Gemini Pro 免费试用操作步骤, 谷歌 aistudio 使用入口

最近的榜首又被Gemini给霸占了&#xff0c;很多童鞋想要体验一翻 Gemini免费库模型更新了 Gemini2.0向所有人开放了&#xff01;使用了真香 目前呢2.0flash和Gemini-2.0-Flash-Thinking-Exp、Gemini-2.0-Flash-Thinking-Exp-with-apps已经免费给所有注册用户开放了&#xff0c…

【数据结构】(7) 栈和队列

一、栈 Stack 1、什么是栈 栈是一种特殊的线性表&#xff0c;它只能在固定的一端&#xff08;栈顶&#xff09;进行出栈、压栈操作&#xff0c;具有后进先出的特点。 2、栈概念的例题 答案为 C&#xff0c;以C为例进行讲解&#xff1a; 第一个出栈的是3&#xff0c;那么 1、…

安宝特方案 | AR助力制造业安全巡检智能化革命!

引言&#xff1a; 在制造业中&#xff0c;传统巡检常面临流程繁琐、质量波动、数据难以追溯等问题。安宝特AR工作流程标准化解决方案&#xff0c;通过增强现实AR技术&#xff0c;重塑制造业安全巡检模式&#xff0c;以标准化作业流程为核心&#xff0c;全面提升效率、质量与…

语言月赛 202308【小粉兔做麻辣兔头】题解(AC)

》》》点我查看「视频」详解》》》 [语言月赛 202308] 小粉兔做麻辣兔头 题目描述 粉兔喜欢吃麻辣兔头&#xff0c;麻辣兔头的辣度分为若干级&#xff0c;用数字表示&#xff0c;数字越大&#xff0c;兔头越辣。为了庆祝粉兔专题赛 #1 的顺利举行&#xff0c;粉兔要做一些麻…

Dify Ollama本地私有化模型实践

今天给大家带来一篇deepseek本地部署&#xff0c;笔者最近由于研究AI大模型应用开发&#xff0c;笔记较少&#xff0c;后面将持续输出关于AI行业应用知识&#xff0c;请大家继续关注&#xff0c;话不多说&#xff0c;开始吧&#xff0c;啊哈哈。 DeepSeek 呢&#xff0c;最近十…

Kafka中的KRaft算法

我们之前的Kafka值依赖于Zookeeper注册中心来启动的&#xff0c;往里面注册我们节点信息 Kafka是什么时候不依赖Zookeeper节点了 在Kafka2.8.0开始就可以不依赖Zookeeper了 可以用KRaft模式代替Zookeeper管理Kafka集群 KRaft Controller和KRaft Leader的关系 两者关系 Lea…

GitPuk快速安装配置教程(入门级)

GitPuk是一款国产开源免费的代码管理工具&#xff0c;工具简洁易用&#xff0c;开源免费&#xff0c;本文将讲解如何快速安装和配置GitPuk&#xff0c;以快速入门上手。 1、安装 支持 Windows、Mac、Linux、docker 等操作系统。 1.1 Linux安装&#xfeff; 以下以Centos7安装…

2025年02月08日Github流行趋势

项目名称&#xff1a;anything-llm 项目地址url&#xff1a;https://github.com/Mintplex-Labs/anything-llm项目语言&#xff1a;JavaScript历史star数&#xff1a;34323今日star数&#xff1a;675项目维护者&#xff1a;timothycarambat, shatfield4, MrSimonC, franzbischof…

【C语言标准库函数】指数与对数函数:exp(), log(), log10()

目录 一、头文件 二、函数简介 2.1. exp(double x) 2.2. log(double x) 2.3. log10(double x) 三、函数实现&#xff08;概念性&#xff09; 3.1. exp(double x) 的模拟实现 3.2. log(double x) 和 log10(double x) 的模拟实现 四、注意事项 4.1. exp(double x) 的注…

Linux之kernel(1)系统基础理论(1)

Linux之Kernel(1)系统基础理论(1) Author: Once Day Date: 2025年2月6日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Linux内核知识_Once-Day的…

从 Facebook 到元宇宙:社交网络的技术进化与前景

引言 社交网络的演变不仅仅是技术进步的体现&#xff0c;更是人类沟通方式革命的缩影。从 Facebook 的诞生到元宇宙的兴起&#xff0c;我们见证了社交互动从简单的信息交换到沉浸式虚拟体验的转变。本文将探讨这一技术演进的历程&#xff0c;并展望社交网络在元宇宙时代的新形…

内容中台赋能人工智能技术提升业务创新能力

内容概要 在当今快速变化的市场环境中&#xff0c;企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构&#xff0c;能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合&#xff0c;企业能够将海量的数据和信息转化为有价…

qt部分核心机制

作业 1> 手动将登录项目实现&#xff0c;不要使用拖拽编程 并且&#xff0c;当点击登录按钮时&#xff0c;后台会判断账号和密码是否相等&#xff0c;如果相等给出登录成功的提示&#xff0c;并且关闭当前界面&#xff0c;发射一个跳转信号&#xff0c;如果登录失败&#…

深度解析全钢陶瓷防静电地板在机房装修中应用较多的原因

全钢陶瓷防静电地板之所以在机房装修中应用较多&#xff0c;是因为它结合了全钢结构和陶瓷面层的双重优势&#xff0c;能够满足高要求场景&#xff08;如数据中心、实验室、医疗设施等&#xff09;对防静电性能、承重能力、耐用性及环境适应性的综合需求。以下是具体原因分析&a…

数据表中的视图操作

文章目录 一、视图概述二、为什么要使用视图三、创建视图四、查看视图 一、视图概述 小学的时候&#xff0c;每年都会举办一次抽考活动&#xff0c;意思是从每一个班级里面筛选出几个优秀的同学去参加考试&#xff0c;这时候很多班级筛选出来的这些同学就可以临时组成一个班级…

zzcms接口index.php id参数存在SQL注入漏洞

zzcms接口index.php id参数存在SQL注入漏洞 漏洞描述 ZZCMS 2023中发现了一个严重漏洞。该漏洞影响了文件/index.php中的某些未知功能,操纵参数id会导致SQL注入,攻击可能是远程发起的,该漏洞已被公开披露并可被利用。攻击者可通过sql盲注等手段,获取数据库信息。 威胁等级:…

Mobaxterm上传下载文件

上传文件 ctrl 右击,选择send file use z-modem 弹窗选择要上传的文件即可 下载文件 输入sz xxx.log ctrl 右击,选择receive file use z-modem 弹窗选择要文件下载的路径即可

cs106x-lecture2(上)(Autumn 2017)

打卡cs106x(Autumn 2017)-lecture2 1、parameterMysteryBCA What is the output of the following code? void mystery(int& b, int c, int& a) {a;b--;c a; } ​ int main() {int a 5;int b 2;int c 8;mystery(c, a, b);cout << a << " "…

e2studio开发RA2E1(9)----定时器GPT配置输入捕获

e2studio开发RA2E1.9--定时器GPT配置输入捕获 概述视频教学样品申请硬件准备参考程序源码下载选择计时器时钟源UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback ()printf输出重定向到串口定时器输入捕获配…

JVM虚拟机以及跨平台原理

相信大家已经了解到Java具有跨平台的特性&#xff0c;即“一次编译&#xff0c;到处运行”&#xff0c;例如在Windows下编写的程序&#xff0c;无需任何修改就可以在Linux下运行&#xff0c;这是C和C很难做到的。 那么&#xff0c;跨平台是怎样实现的呢&#xff1f;这就要谈及…