认识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.mzph.cn/bicheng/70508.shtml

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

相关文章

方波的基波和谐波详细推导,以及matlab验证[电路原理---2]

最近要滤波&#xff0c;从1KHZ 方波中获得正弦波&#xff0c;这让我们要对方波的频谱有具体的了解。虽然楼主一年前刚学过傅里叶。但也是忘的干干净净查阅资料后终于是整理出来。用漂亮的latex打出来了&#xff0c;为自己留存一份记录&#xff0c;也分享给大家学习。 方波的基…

计算机组成原理(3)

计算机组成原理&#xff08;3&#xff09; 存储器层次结构存储器概述存储器分类存储器性能指标 半导体随机存储SRAM和DRAM 存储器层次结构 主存-辅存&#xff1a;实现了虚拟存储系统&#xff0c;解决了主存容量不足的问题&#xff1b; Cache-主存&#xff1a;解决了主存于CPU速…

2024最新版Java面试题及答案,【来自于各大厂】

发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全~ 篇幅限制就只能给大家展示小册部分内容了&#xff0c;需要完整版的及Java面试宝典小伙伴点赞转发&#xff0c;关注我后在【翻到最下方&#xff0c;文尾点击名片】即可免费获取…

DeepSeek-V3 论文解读:大语言模型领域的创新先锋与性能强者

论文链接&#xff1a;DeepSeek-V3 Technical Report 目录 一、引言二、模型架构&#xff1a;创新驱动性能提升&#xff08;一&#xff09;基本架构&#xff08;Basic Architecture&#xff09;&#xff08;二&#xff09;多令牌预测&#xff08;Multi-Token Prediction&#xf…

Mac 基于Ollama 本地部署DeepSeek离线模型

最近节日期间最火的除了《哪吒》就是deepseek了&#xff0c;毕竟又让西方各个层面都瑟瑟发抖的产品。DeepSeek凭借其强大的AI能力真的是在全球多个领域展现出强大的影响力。由于受到外部势力的恶意攻击倒是deepseek官方服务不稳定&#xff0c;国内其他厂家的适配版本也不是很稳…

51单片机之引脚图(详解)

8051单片机引脚分类与功能笔记 1. 电源引脚 VCC&#xff08;第40脚&#xff09;&#xff1a;接入5V电源&#xff0c;为单片机提供工作电压。GND&#xff08;第20脚&#xff09;&#xff1a;接地端&#xff0c;确保电路的电位参考点。 2.时钟引脚 XTAL1&#xff08;第19脚&a…

力扣刷题 题11,12

题目11 思路&#xff1a;设置左右指针 left和 right 指针指向数组的开始和末尾&#xff0c;max_water 用于记录最大容量初始为0。利用while循环left<right&#xff0c;移动指针比较数组元素 height[left] 和 height[right] 的大小&#xff0c;移动较短的那条线的指针&#x…

使用Python实现PDF与SVG相互转换

目录 使用工具 使用Python将SVG转换为PDF 使用Python将SVG添加到现有PDF中 使用Python将PDF转换为SVG 使用Python将PDF的特定页面转换为SVG SVG&#xff08;可缩放矢量图形&#xff09;和PDF&#xff08;便携式文档格式&#xff09;是两种常见且广泛使用的文件格式。SVG是…

爬虫工程师分享:获取京东商品详情SKU数据的技术难点与攻破方法

在电商数据领域&#xff0c;京东商品详情页的SKU数据是许多爬虫工程师的目标。这些数据包含了商品的价格、库存、规格等关键信息&#xff0c;对于市场分析、价格监控等应用场景至关重要。然而&#xff0c;获取这些数据并非易事&#xff0c;京东作为国内电商巨头&#xff0c;其反…

【DeepSeek × Postman】请求回复

新建一个集合 在 Postman 中创建一个测试集合 DeepSeek API Test&#xff0c;并创建一个关联的测试环境 DeepSeek API Env&#xff0c;同时定义两个变量 base_url 和 api_key 的步骤如下&#xff1a; 1. 创建测试集合 DeepSeek API Test 打开 Postman。点击左侧导航栏中的 Co…

使用java代码操作rabbitMQ收发消息

SpringAMQP 将来我们开发业务功能的时候&#xff0c;肯定不会在控制台收发消息&#xff0c;而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也…

【WB 深度学习实验管理】使用 PyTorch Lightning 实现高效的图像分类实验跟踪

本文使用到的 Jupyter Notebook 可在GitHub仓库002文件夹找到&#xff0c;别忘了给仓库点个小心心~~~ https://github.com/LFF8888/FF-Studio-Resources 在机器学习项目中&#xff0c;实验跟踪和结果可视化是至关重要的环节。无论是调整超参数、优化模型架构&#xff0c;还是监…

【AIGC】冷启动数据与多阶段训练在 DeepSeek 中的作用

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;冷启动数据的作用冷启动数据设计 &#x1f4af;多阶段训练的作用阶段 1&#xff1a;冷启动微调阶段 2&#xff1a;推理导向强化学习&#xff08;RL&#xff0…

AWK系统学习指南:从文本处理到数据分析的终极武器 介绍

目录 一、AWK核心设计哲学解析 1.1 记录与字段的原子模型 1.2 模式-动作范式 二、AWK编程语言深度解析 2.1 控制结构 说明&#xff1a; 2.2 关联数组 代码说明&#xff1a; 示例输入和输出&#xff1a; 注意事项&#xff1a; 2.3 内置函数库 三、高级应用技巧 3.1…

链表和 list

一、单链表的模拟实现 1.实现方式 链表的实现方式分为动态实现和静态实现两种。 动态实现是通过 new 申请结点&#xff0c;然后通过 delete 释放结点的形式构造链表。这种实现方式最能体 现链表的特性&#xff1b; 静态实现是利用两个数组配合来模拟链表。一个表示数据域&am…

大模型推理——MLA实现方案

1.整体流程 先上一张图来整体理解下MLA的计算过程 2.实现代码 import math import torch import torch.nn as nn# rms归一化 class RMSNorm(nn.Module):""""""def __init__(self, hidden_size, eps1e-6):super().__init__()self.weight nn.Pa…

MySQL 8.0.41安装教程(2025年2月8号)

下载网址&#xff1a;https://www.mysql.com/cn/downloads/ 点击 我选择的是第二个离线安装 点击之后&#xff0c;选择直接下载&#xff1a; 下载完成双击&#xff1a; 我选择的是自定义安装&#xff1a; 右边默认已经存在我选择的8.0.41 点击红框中的&#xff0c;自定义安装路…

WPS中解除工作表密码保护(忘记密码)

1.下载vba插件 项目首页 - WPS中如何启用宏附wps.vba.exe下载说明分享:WPS中如何启用宏&#xff1a;附wps.vba.exe下载说明本文将详细介绍如何在WPS中启用宏功能&#xff0c;并提供wps.vba.exe文件的下载说明 - GitCode 并按照步骤安装 2.wps中点击搜索&#xff0c;输入开发…

Python多版本管理

关注后回复 python 获取相关资料 ubuntu18.04 # ubuntu18 默认版本 Python 2.7.17 apt install python python-dev python-pip# ubuntu18 默认版本 Python 3.6.9 apt install python3 python3-dev python3-pip# ubuntu18 使用 python3.8 apt install python3.8 python3.8-dev#…

基于python多线程多进程爬虫的maa作业站技能使用分析

基于python多线程多进程爬虫的maa作业站技能使用分析 技能使用分析 多线程&#xff08;8核&#xff09; import json import multiprocessing import requests from multiprocessing.dummy import Pooldef maa(st):url "https://prts.maa.plus/copilot/get/"m …