C++ 归并排序OJ

目录

1、912. 排序数组

2、LCR 170. 交易逆序对的总数

3、315. 计算右侧小于当前元素的个数

4、493. 翻转对


1、912. 排序数组

 

思路:本次使用归并排序 ,快速排序相当于二叉树的前序遍历,而归并排序相当于后序遍历。

  • 归并排序是一种有效的排序算法,采用分治策略,将问题分解成一系列更小的问题,然后解决这些小问题,并将解决方案合并以产生原始问题的解决方案。下面是对这个过程的逐步解释。
  • 归并排序的工作原理

    归并排序通过递归地将数组分成越来越小的部分,直到每个部分只有一个元素(自然是有序的),然后将这些有序的部分合并成较大的有序部分,直至整个数组排序完成。这个过程中,合并操作是通过比较来自两个不同部分的元素并选择较小的那个来实现的,这保证了合并后的数组也是有序的。

  • 性能

    归并排序的时间复杂度为O(n log n),其中n是数组的长度。这是因为每一层递归操作都需要遍历整个数组(O(n)),而递归树的深度为log n。归并排序需要额外的存储空间来存储临时数组,因此它的空间复杂度为O(n)。

class Solution {
public:vector<int> tmp;vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());mergeSort(nums, 0, nums.size() - 1);return nums;}void mergeSort(vector<int>& nums, int left, int right) {if (left >= right)return;int mid = left + ((right - left) >> 1);mergeSort(nums, left, mid);mergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right)tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];while (cur1 <= mid)tmp[i++] = nums[cur1++];while (cur2 <= right)tmp[i++] = nums[cur2++];for (int i = left; i <= right; i++)nums[i] = tmp[i - left];}
};
  • vector<int> tmp;:一个临时向量,用于归并排序过程中的合并操作。
  • vector<int> sortArray(vector<int>& nums)

    • 接受一个整数向量nums作为输入,并返回排序后的向量。
    • tmp.resize(nums.size());:首先,将临时向量tmp的大小调整为与输入向量nums相同,确保有足够的空间进行合并操作。
    • mergeSort(nums, 0, nums.size() - 1);:调用mergeSort方法对整个数组进行排序,传入的参数是数组的左右边界索引。
  • void mergeSort(vector<int>& nums, int left, int right)

    • 这是一个递归方法,用于对数组nums从索引leftright进行排序。
    • 如果left大于等于right,表示区间内最多只有一个元素,不需要排序,直接返回。
    • 计算中点mid,将数组分为两部分:leftmidmid + 1right
    • 递归调用mergeSort分别对这两部分进行排序。
    • 使用三个指针cur1cur2i,分别指向左半部分的起始位置、右半部分的起始位置和临时数组tmp的起始位置。
    • 通过比较cur1cur2所指向的元素,选择较小的元素放入tmp中,并移动相应的指针和i
    • 如果左半部分或右半部分有剩余元素,将它们复制到tmp中。
    • 将临时数组tmp中的元素复制回原数组nums的相应位置。

2、LCR 170. 交易逆序对的总数

 思路:采用分支策略,使用归并排序处理。利用归并排序先在左区间统计逆序对个数,再统计右区间,左右区间统计完回到上层,左右区间作为左区间继续递归统计,递归排序既可以排升序也可以排降序,都可以解决本题。

升序: 找出该数之前有多少个比它大的

class Solution {
public:int tmp[50010];int reversePairs(vector<int>& record) {return mergeSort(record, 0, record.size() - 1);}int mergeSort(vector<int>& record, int left, int right) {if (left >= right)return 0;int mid = left + ((right - left) >> 1);int ret = 0;ret += mergeSort(record, left, mid);ret += mergeSort(record, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right) {if (record[cur1] <= record[cur2]) {tmp[i++] = record[cur1++];} else {ret += mid - cur1 + 1;tmp[i++] = record[cur2++];}}while (cur1 <= mid) {tmp[i++] = record[cur1++];}while (cur2 <= right) {tmp[i++] = record[cur2++];}for (int i = left; i <= right; i++) {record[i] = tmp[i - left];}return ret;}
};

降序:找出该数之前有多少个比它小的

class Solution {
public:int tmp[50010];int reversePairs(vector<int>& record) {return mergeSort(record, 0, record.size() - 1);}int mergeSort(vector<int>& record, int left, int right) {if (left >= right)return 0;int mid = left + ((right - left) >> 1);int ret = 0;ret += mergeSort(record, left, mid);ret += mergeSort(record, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right) {if (record[cur1] <= record[cur2]) {tmp[i++] = record[cur2++];} else {ret += right - cur2 + 1;tmp[i++] = record[cur1++];}}while (cur1 <= mid) {tmp[i++] = record[cur1++];}while (cur2 <= right) {tmp[i++] = record[cur2++];}for (int i = left; i <= right; i++) {record[i] = tmp[i - left];}return ret;}
};

3、 315. 计算右侧小于当前元素的个数

思路:采用分支策略,使用归并排序处理。但是在我们归并排序的过程中,元素的下标是会跟着变化的,因此我们需要⼀个辅助数组,来将数组元素和对应的下标绑定在⼀起归并,也就是再归并元素的时候,顺势将下标也转移到对应的位置上。

class Solution {
public:vector<int> index;vector<int> ret;int tmpNums[500000];int tmpIndex[500000];vector<int> countSmaller(vector<int>& nums) {int n = nums.size();ret.resize(n);index.resize(n);for (int i = 0; i < n; i++) {index[i] = i;}mergeSort(nums, 0, n - 1);return ret;}void mergeSort(vector<int>& nums, int left, int right) {if (left >= right)return;int mid = left + ((right - left) >> 1);mergeSort(nums, left, mid);mergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right) {if (nums[cur1] <= nums[cur2]) {tmpNums[i] = nums[cur2];tmpIndex[i++] = index[cur2++];} else {ret[index[cur1]] += right - cur2 + 1;tmpNums[i] = nums[cur1];tmpIndex[i++] = index[cur1++];}}while (cur1 <= mid) {tmpNums[i] = nums[cur1];tmpIndex[i++] = index[cur1++];}while (cur2 <= right) {tmpNums[i] = nums[cur2];tmpIndex[i++] = index[cur2++];}for (int j = left; j <= right; j++) {nums[j] = tmpNums[j - left];index[j] = tmpIndex[j - left];}}
};

类成员解释

  • vector<int> index;:用于存储每个元素在原数组中的索引。
  • vector<int> ret;:用于存储最终的结果,即每个元素右侧小于它的元素数量。
  • int tmpNums[500000];:临时数组,用于归并排序过程中存储中间结果。
  • int tmpIndex[500000];:临时数组,用于存储归并排序过程中元素的索引。

方法解释

  • vector<int> countSmaller(vector<int>& nums):这是主方法,用于初始化并开始归并排序过程。

    • 初始化retindex数组。
    • 调用mergeSort方法进行归并排序。
  • void mergeSort(vector<int>& nums, int left, int right):这是归并排序的实现方法。

    • 如果left大于等于right,则不需要排序,直接返回。
    • 计算中点mid,然后递归地对左半部分和右半部分进行归并排序。
    • 接下来是归并过程,其中比较关键的是在比较左右两部分的元素时,如果左边的元素大于右边的元素,那么意味着左边的这个元素大于右边所有未被合并的元素,因此ret[index[cur1]]需要加上右边剩余元素的数量(right - cur2 + 1)。
    • 最后,将排序好的部分复制回原数组nums和索引数组index

4、493. 翻转对

思路:采用分支策略,使用归并排序处理。

降序—找元素后面小的 

class Solution {
public:int tmp[50001];int reversePairs(vector<int>& nums) {return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right) {if (left >= right)return 0;int ret = 0;int mid = left + ((right - left) >> 1);ret += mergeSort(nums, left, mid);ret += mergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = left;while (cur1 <= mid) {while (cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) {cur2++;}if (cur2 > right)break;ret += right - cur2 + 1;cur1++;}cur1 = left, cur2 = mid + 1;while (cur1 <= mid && cur2 <= right) {tmp[i++] = nums[cur1] < nums[cur2] ? nums[cur2++] : nums[cur1++];}while (cur1 <= mid) {tmp[i++] = nums[cur1++];}while (cur2 <= right) {tmp[i++] = nums[cur2++];}for (int j = left; j <= right; j++) {nums[j] = tmp[j];}return ret;}
};
  • int reversePairs(vector<int>& nums):这是主方法,用于开始归并排序过程,并返回重要翻转对的数量。
  • int mergeSort(vector<int>& nums, int left, int right):这是归并排序的实现方法,同时也是计算重要翻转对的核心方法。
    • 如果left大于等于right,则不需要处理,直接返回0。
    • 通过递归调用mergeSort方法,分别对数组的左半部分和右半部分进行排序,并计算左半部分和右半部分内部各自的重要翻转对数量,累加到ret
    • 在合并两个已排序的部分之前,先计算跨越左右部分的重要翻转对数量。这是通过两个指针cur1cur2实现的,cur1遍历左半部分,cur2遍历右半部分,当nums[cur2] >= nums[cur1] / 2.0时,cur2向右移动,直到找到第一个使得nums[i] > 2*nums[j]j,此时right - cur2 + 1即为对于当前cur1指向的元素,满足条件的翻转对数量。
    • 然后,进行正常的归并排序合并操作,将两个部分合并为一个有序数组。
    • 最后,将临时数组tmp中的排序结果复制回原数组nums

升序—找元素前面大的

class Solution {
public:int tmp[50001];int reversePairs(vector<int>& nums) {return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right) {if (left >= right)return 0;int ret = 0;int mid = left + ((right - left) >> 1);ret += mergeSort(nums, left, mid);ret += mergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = left;while (cur2 <= right) {while (cur1 <= mid && nums[cur1] / 2.0 <= nums[cur2]) {cur1++;}if (cur1 > right)break;ret += mid - cur1 + 1;cur2++;}cur1 = left, cur2 = mid + 1;while (cur1 <= mid && cur2 <= right) {tmp[i++] = nums[cur1] < nums[cur2] ? nums[cur1++] : nums[cur2++];}while (cur1 <= mid) {tmp[i++] = nums[cur1++];}while (cur2 <= right) {tmp[i++] = nums[cur2++];}for (int j = left; j <= right; j++) {nums[j] = tmp[j];}return ret;}
};

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

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

相关文章

Jenkins设置使用163邮箱发送邮件

目录 一、下载需要的插件 二、开通163邮箱的SMTP服务 三、配置邮箱&#xff0c;测试发送 1、配置Jenkins Location 2、配置Extended E-mail Notification 扩展邮件通知 3、配置默认触发器&#xff08;可先不配置&#xff09; ​编辑 4、配置默认的邮件通知 5、测试邮箱…

BUUCTF-DASBOOK1

[第一章][1.3.5 案例解析][极客大挑战 2019]Http 1 1.启动靶机 2.查看源代码&#xff0c;发现有链接 3.点击链接&#xff0c;跳转页面有提示&#xff0c;意思是&#xff1a;它并不来自于https:/Sycsecret.buuoj.cn 打开hackbar&#xff0c;如图所示&#xff0c;然后执行 4.得到…

PyTorch2.0 环境搭建详细步骤(Nvidia显卡)

Step 1 、查看显卡驱动版本 Step2、下载CUDA 11.7 或者11.8&#xff08;我自己用的这个&#xff09;也行,稍后我会贴出来版本匹配对应表 CUDA Toolkit - Free Tools and Training | NVIDIA Developer Step3、下载CUDNN cuDNN 9.0.0 Downloads | NVIDIA Developer Step4、安装…

(文末送书)直击前沿技术:《低代码平台开发实践:基于React》

目录 前言 一、React与低代码平台的结合优势 二、基于React的低代码平台开发挑战 三、基于React的低代码平台开发实践 四、书籍推荐 《低代码平台开发实践&#xff1a;基于React》 1、图书介绍 2、适用人群 3、 作者简介 4、写书原由 5、解决问题 6、书…

Application

1.Application的生命周期 自定义Application package com.tiger.chapter06;import android.app.Application; import android.content.res.Configuration; import android.util.Log;import androidx.annotation.NonNull;public class MyApplication extends Application {//在…

1.1 深度学习和神经网络

首先要说的是&#xff1a;深度学习的内容&#xff0c;真的不难。你要坚持下去。 神经网络 这就是一个神经网络。里面的白色圆圈就是神经元。神经元是其中最小的单位。 神经网络 单层神经网络&#xff1a; 感知机 &#xff08;双层神经网络&#xff09; 全连接层&#xff1a; …

Unity2013.1.19_DOTS_Burst compiler

Unity2013.1.19_DOTS_Burst compiler DOTS是一种新产品&#xff0c;现在尚在起步阶段。由于它处于持续发展中&#xff0c;随着我们努力使其达到最佳状态&#xff0c;您将看到API会不断演变和日趋成熟。 DOTS包含以下元素&#xff1a; 实体组件系统(ECS) - 提供使用面向数据的…

人工智能艺术的简要时间表

一、简述 技术在任何形式的艺术发展中始终发挥着关键作用。从通过化学发明颜色到通过数学发现分形&#xff1a;艺术、文化和技术是无法完全分开的三个维度。 计算机也不例外&#xff0c;它们从一开始就被用来帮助艺术家&#xff0c;常常揭示出我们无法看到的美丽的复杂性。数字…

It is also possible that a host key has just been changed

问题&#xff1a;ssh失败&#xff0c;提示如上图 分析: ssh的key存在上图里的路径里。 解决&#xff1a;win10删这个文件C:\Users\admin\.ssh\known_hosts , linux删这个文件.ssh\known_hosts ,或者删除这个文件里的制定ip的那一行&#xff0c;例如“106.1.1.22 ecdsa-sha2-…

JavaWeb - 2 - HTML、CSS

什么是HTML、CSS&#xff1f; HTML&#xff08;HyperText Markup Language&#xff09;&#xff1a;超文本标记语言 超文本&#xff1a;超越了文本的限制&#xff0c;比普通文本更强大&#xff0c;除了文字信息&#xff0c;还可以定义图片、音频、视频等内容 标记语言&…

multiprocessing Event实现中断进程或程序

参考&#xff1a;https://www.cnblogs.com/MoKinLi/p/17931515.html import multiprocessing import timedef worker(event, value):while True:# 检查事件是否被设置if event.is_set():# 事件被设置&#xff0c;中断程序break# 模拟工作time.sleep(1)print(f"Working: {…

Excel小技巧 (2) - 如何去除和增加前导0

1. 如何去除前导0 公式&#xff1a;SUBSTITUTE(A2,0,"")&#xff0c;然后拖动十字架&#xff0c;同步所有列数据&#xff0c;轻松搞定。 2. 如何补充前导0 公式&#xff1a;TEXT(D2,"0000000") &#xff0c;0的个数是数字的完整位数。然后拖动十字架&a…

【概要】软件测试

&#x1f349;CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一&#xff5c;统计学&#xff5c;干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项&#xff0c;参与研究经费10w、40w级横向 文…

Docker网络配置

目录 一.Docker网络模式 1.1bridge模式(默认模式) 1.2host模式&#xff08;仅主机模式&#xff09; 1.3初识网络模式 1.4查看桥接模式的特点 1.5查看仅主机模式的特点 二.Docker桥接模式 三.host模式 四.自定义网络 一.Docker网络模式 Docker在创建容器时有四种网络模式&am…

结合大象机器人六轴协作机械臂myCobot 280 ,解决特定的自动化任务和挑战!(下)

Limo Pro 小车建图导航 引言 前景提要&#xff1a;我们在上文介绍了使用LIMO cobot 实现一个能够执行复杂任务的复合机器人系统的应用场景的项目&#xff0c;从以下三个方面&#xff1a;概念设计、系统架构以及关键组件。 本文主要深入项目内核的主要部分&#xff0c;同样也主要…

四桥臂三相逆变器动态电压恢复器(DVR)MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 简介 四桥臂三相逆变器 电路 的一般形式如图 1&#xff0c;为 便于分析 &#xff0c;将其等效成图所示的电路 。以直流母线电压Ud的 1&#xff0f;2处为参考点 &#xff0c;逆变器三相和零线相 输 出可等效成…

[数据结构]队列

1.队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾 出队列&#xff1a;进行删除操作的一端称为队头 2…

基于 HBase Phoenix 构建实时数仓(1)—— Hadoop HA 安装部署

目录 一、主机规划 二、环境准备 1. 启动 NTP 时钟同步 2. 修改 hosts 文件 3. 配置所有主机间 ssh 免密 4. 修改用户可打开文件数与进程数&#xff08;可选&#xff09; 三、安装 JDK 四、安装部署 Zookeeper 集群 1. 解压、配置环境变量 2. 创建配置文件 3. 创建新…

mac电脑版MATLAB R2023b for Mac中文激活版

MATLAB R2023b for Mac&#xff1a;科学计算的终极工具 软件下载&#xff1a;MATLAB R2023b for Mac中文激活版下载 &#x1f52c; 探索科学&#xff0c;无限可能 MATLAB R2023b for Mac&#xff0c;助您深入挖掘科学计算的奥秘。从数据分析、算法设计到可视化展示&#xff0c;…

基于GitBucket的Hook构建ES检索PDF等文档全栈方案

背景 之前已简单使用ES及Kibana和在线转Base64工具实现了检索文档的demo&#xff0c;预期建设方案是使用触发器类型从公共的文档源拉取最新的文件&#xff0c;然后调用Java将文件转Base64后入ES建索引&#xff0c;再提供封装接口给前端做查询之用。 由于全部内容过长&#xff…