分治算法(7)_归并排序_计算右侧小于当前元素的个数

news/2024/10/15 15:52:38/

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

分治算法(7)_归并排序_计算右侧小于当前元素的个数

收录于专栏【经典算法练习】
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

温馨提示: 

1. 题目链接

2. 题目描述

3. 解法

算法思路:

代码展示:


温馨提示: 

这一道题的解法与求数组中的逆序对的解法是类似的, 但是这一道题要求的不是求总的个数, 而是要返回一个数组, 记录每一个元素的右边有多少个元素比自己小.所以这里将求逆序对的算法思路并不会详细详解, 如果还不是很了解的宝子们可以先去下面的博客查看:

分治算法(6)_归并排序_交易逆序对的总数-CSDN博客

1. 题目链接

OJ链接 :  计算右侧小于当前元素的个数

2. 题目描述

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例 1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素

示例 2:

输入:nums = [-1]
输出:[0]

示例 3:

输入:nums = [-1,-1]
输出:[0,0]

3. 解法

算法思路:

这一道题的解法与求数组中的逆序对的解法是类似的,但是这⼀道题要求的不是求总的个数,而
是要返回一个数组,记录每一个元素的右边有多少个元素比自己小。
但是在我们归并排序的过程中,元素的下标是会跟着变化的,因此我们需要⼀个辅助数组,来将
组元素和对应的下标绑定在⼀起
归并,也就是再归并元素的时候,顺势将下标也转移到对应的位置
上。
由于我们要快速统计出某⼀个元素后面有多少个比它小的,因此我们可以利用求逆序对的第二种方法。

算法流程:

• 创建两个全局的数组:
    vector<int> index:记录下标
    vector<int> ret:记录结果
    index 用来与原数组中对应位置的元素绑定,ret 用来记录每个位置统计出来的逆序对的个数。

• countSmaller() 主函数:
a.计算 nums 数组大小为 n;
b.初始化定义的两个全局的数组;
    i.为两个数组开辟大小为 n 的空间
    ii.index 初始化为数组下标;
    iii.ret 初始化为 0
c.调用 mergeSort() 函数,并且返回 ret 结果数组。


• void mergeSort(vector<int>&nums, int left, int right) 函数:
函数设计:通过修改全局的数组 ret, 统计出每⼀个位置对应的逆序对的数量,并且排序;
无需返回值,因为直接对全局变量修改,当函数结束的时候,全局变量已经被修改成最后的结果。

• mergeSort() 函数流程:
a.定义递归出口:left >= right 时,直接返回;
b.划分区间:根据中点 mid,将区间划分为[left, mid][mid + 1, right];
c.统计左右两个区间逆序对的数量:
    i.统计左边区间[left, mid] 中每个元素对应的逆序对的数量到 ret 数组中,并排序;
    ii.统计右边区间[mid + 1, right] 中每个元素对应的逆序对的数量到 ret 数组中,并排序。
d.合并左右两个有序区间,并且统计出逆序对的数量:
    i.创建两个大小为 right - left + 1 大小的辅助数组:
        • numsTmp: 排序用的辅助数组;
        • indexTmp:处理下标用的辅助数组。
ii.初始化遍历数组的指针:cur1 = left(遍历左半部分数组)cur2 = mid + 1(遍历右半边数
组)dest = 0(遍历辅助数组)curRet(记录合并时产⽣的逆序对的数量);
iii.循环合并区间:
    • 当 nums[cur1] <= nums[cur2] 时:
        ◦ 说明此时[mid + 1, cur2) 之间的元素都是小于 nums[cur1] 的,需要累加到 ret 数
        组的 indext[cur1] 位置上(因为 index 存储的是元素对应位置在原数组中的下标)
        ◦ 归并排序:不仅要将数据放在对应的位置上,也要将数据对应的坐标也放在对应的位
        置上,使数据与原始的下标绑定在⼀起移动。
    • 当 nums[cur1] > nums[cur2] 时,无需统计,直接归并,注意 index 也要跟着归并。
iv.处理归并排序中剩余的元素;
    • 当左边有剩余的时候,还需要统计逆序对的数量;
    • 当右边还有剩余的时候,无需统计,直接归并。
v.将辅助数组的内容替换到原数组中去;

代码展示:

class Solution 
{vector<int> ret;vector<int> index;//记录 nums 中当前元素的原始下标int tmpnums[100010];int tmpindex[100010];public:vector<int> countSmaller(vector<int>& nums) {int n = nums.size();ret.resize(n);index.resize(n);//初始化index数组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) >> 1;//[left, mid] [mid + 1, right]//2. 先处理左右两部分mergesort(nums, left, mid), mergesort(nums, mid + 1, right);//3. 处理一左一右的情况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];}}
};

 


http://www.ppmy.cn/news/1539490.html

相关文章

全面掌握 Linux 服务管理:从入门到精通

全面掌握 Linux 服务管理&#xff1a;从入门到精通 引言 在 Linux 系统中&#xff0c;服务管理是系统管理员和开发者的基本技能之一。无论是启动、停止、重启还是查看服务状态&#xff0c;systemctl 命令都能让你轻松完成这些操作。今天&#xff0c;我们将深入探讨如何使用 sy…

Linux操作系统——外存的管理(实验报告)

实验 Linux系统外存管理 一、实验目的 熟练Linux系统外存管理的方法与命令。 二、实验环境 硬件&#xff1a;PC电脑一台&#xff0c;网络正常。 配置&#xff1a;win10系统&#xff0c;内存大于8G 硬盘500G及以上。 软件&#xff1a;VMware、Ubuntu16.04。 三、实验内容 …

Python和CUDA(C++)量子退火和伊辛二次算法模型

&#x1f3af;要点 简化量子退火或离散优化算法处理&#xff0c;使用张量网络模拟和动态系统方法及神经网络逼近。实现并行退火算法和CUDA支持下穷举搜索法。使用大都会算法模拟二维自旋玻璃伊辛模型并测量磁化率、比热容和能量。对比其他组合优化解方法&#xff0c;使用英伟达…

上百种【基于YOLOv8/v10/v11的目标检测系统】目录(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

待更新(持续更新&#xff09;&#xff0c;早关注&#xff0c;不迷路............................................................................... 目标检测系统操作说明【用户使用指南】&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型&#xff…

玩机搞机基本常识-----如何在 Android 中实现默认开启某个功能 修改方法列举

我们有时候需要对安卓系统进行修改。实现其中的某些功能。让用户使用得心应手。节约时间。那么如果要实现系统中的有些功能选项开启或者关闭。就需要对系统有一定的了解。那么在 Android 中实现默认开启某个功能可以通过以下几种方式&#xff1a; 一、在应用的设置中添加选项 …

【mysql】统计两个相邻任务/事件的间隔时间以及每个任务的平均用时

准备步骤1. 设置查询参数部分1.1 设置需要分析的起始时间1.2. 设置需要分析的时间的长度&#xff08;分析的结束时间&#xff09;1.3. 设置分析内容1.4. 设置需要分析的表和字段 2. 自动计算分析2.1 设置起始序号2.2. 筛选user_log表数据并生成带序号的临时表temp_ria2.3. 通过…

Elasticsearch Suggester

概述 Elasticsearch里设计了4 种类别的 Suggester Term Suggester&#xff1a;词条建议器。对给输入的文本进进行分词&#xff0c;为每个分词提供词项建议。Phrase Suggester&#xff1a;短语建议器&#xff0c;在term的基础上&#xff0c;会考量多个term之间的关系Completio…

什么是DApp?DApp开发指南

一、什么是DApp&#xff1f; DApp&#xff08;Decentralized Application&#xff09;&#xff0c;即去中心化应用&#xff0c;是一种基于区块链技术开发的应用程序&#xff0c;与传统的中心化应用不同&#xff0c;DApp不依赖单一服务器或管理主体&#xff0c;而是利用去中心化…