【分治】归并排序

news2024/9/25 15:29:30

【分治】归并排序

  • 1. 排序数组
    • 1. 1题目来源
    • 1.2 题目描述
    • 1.3 题目解析
  • 2. LCR 170. 交易逆序对的总数
    • 2. 1题目来源
    • 2.2 题目描述
    • 2.3 题目解析
  • 3. 计算右侧小于当前元素的个数
    • 3. 1题目来源
    • 3.2 题目描述
    • 3.3 题目解析

1. 排序数组

1. 1题目来源

912. 排序数组

1.2 题目描述

给你一个整数数组 nums,请你将该数组升序排列。

  1. 示例 1:
    输入:nums = [5,2,3,1]
    输出:[1,2,3,5]
  2. 示例 2:
    输入:nums = [5,1,1,2,0,0]
    输出:[0,0,1,1,2,5]

提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104

1.3 题目解析

本次实现我们使用归并的思想,这里也可以使用其他的排序算法,比如快排。而快排我们在上一期也进行讲解过了——分支-快速排序,快排的原理在八大排序算法中也有详细的讲解,不了解的可以复习一下。

class Solution {
public:
    void MergeSort(vector<int>& nums, int left, int right, vector<int>& temp)
    {
        if (left >= right) return;

        //1. 分解
        int mid = left + (right - left) / 2;
        MergeSort(nums, left, mid, temp);
        MergeSort(nums, mid + 1, right, temp);

        // 合并
        int l = left, r = mid + 1;
        int k = left;
        while (l <= mid && r <= right)
        {
            if (nums[l] < nums[r])
                temp[k++] = nums[l++];
            else temp[k++] = nums[r++];
        }

        while (l <= mid)
            temp[k++] = nums[l++];
        while (r <= right)
            temp[k++] = nums[r++];
        
        // 3. 返回
        for (int i = left; i <= right; i++)
        {
            nums[i] = temp[i];
        }
    }

    vector<int> sortArray(vector<int>& nums) 
    {
        vector<int> temp;
        int n = nums.size();
        temp.resize(n);
        MergeSort(nums, 0, n - 1, temp);
        return nums;  
    }
};

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

2. 1题目来源

[LCR 170. 交易逆序对的总数](https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/description/

2.2 题目描述

在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 record,返回其中存在的「交易逆序对」总数。

示例 1:
输入:record = [9, 7, 5, 4, 6]
输出:8
解释:交易中的逆序对为 (9, 7), (9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4)。

限制:
0 <= record.length <= 50000

2.3 题目解析

这里我们一开始想到的是直接暴力枚举的,但是可以看到0 <= record.length <= 50000,暴力枚举的时间复杂度是O(N^2)肯定是会超时的。所以这里我们不能使用暴力枚举。

在这里插入图片描述

所以这里我们想到了使用归并的方法,这里我们回顾一下归并的方法。归并的方法是先求出中间节点,将其分成左右部分,接着根据左右两部分再次重复上述动作,直到划分出只有一个节点之后,就开始进行重新合并,在此之间就可以进行排序的动作。
在这里插入图片描述

所以在合并的时候我们就可以来实现找逆序对的动作。在我们实现归并的动作时我们可以在实现排序的动作之前将逆序对计算出来。而这个时候对于下次归并来讲是已经有序的了,而对于有序的左右两部分的话我们要计算左右中的逆序对是很好计算的。

因为再上一步我们已经计算出来左右各部分的逆序和,所以就算排好序了也不会影响计算左右的逆序对,反而会更好计算了。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    void MergeSort(vector<int>& nums, int left, int right, vector<int>& temp, int &ret)
    {
        if (left >= right) return;

        int mid = left + (right - left) / 2;
        MergeSort(nums, left, mid, temp, ret);
        MergeSort(nums, mid + 1, right, temp, ret);
        int k = left, l = left, r = mid + 1;
        while (l <= mid && r <= right)
        {
            if (nums[l] <= nums[r]) 
                temp[k++] = nums[l++];
            else 
            {
                ret += mid - l + 1;
                temp[k++] = nums[r++];
            }
        }

        while (l <= mid) 
            temp[k++] = nums[l++];
        while (r <= right) 
            temp[k++] = nums[r++];

        for (int i = left; i <= right; i++)
            nums[i] = temp[i];
    }
    int reversePairs(vector<int>& record) {
        int ret = 0;
        vector<int> temp;
        int n = record.size();
        temp.resize(n);
        MergeSort(record, 0, n - 1, temp, ret);
        return ret;
    }
};

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

3. 1题目来源

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

3.2 题目描述

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

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

提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104

3.3 题目解析

本题其实和上一题LCR 170. 交易逆序对的总数其实是一样的道理,只不过上一题要求的是总数,而本题求的是每一个数据对应前面比他小的数的个数。而这个时候如果我们使用hash的话,数据又是可以重复的无法使用哈希。所以这里最大的难点在于我们在进行归并的时候如何快速的定位到数据,并根据该数据随对应的原始下标进行计数。

所以这里我们要用到一个辅助数组。
在这里插入图片描述
在这里插入图片描述
所以这个时候我们需要定义两个辅助数组,一个辅助原始数组,一个辅助index数组。

采用降序的方式,进行比较。

在这里插入图片描述
所以具体步就是定义temp,index,index_temp, ret四个容器,ret用来存放返回的数据,temp用来辅助原始数组,index用来存放与原始数组的绑定,indx_temp用来辅助index。

  1. 先直接进行归并的常规操作
  2. 判断nums[l] > nums[r]是否成立,如果成立说明找到了一个数据后面的数比前面的数要写,并需要更新此时l标识数据的下标存放到index_temp中。
  3. 后序同样进行归并的操作,并更新小标索引
  4. 不要忘记重新将辅助数组中的数据放回原来的数组中。
class Solution {
public:
    vector<int> temp,index,index_temp, ret;
    void MergeSort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;
        int mid = left + (right - left) / 2;

        MergeSort(nums, left, mid);
        MergeSort(nums, mid + 1, right);

        int l = left, r = mid + 1;
        int k = left;
        
        while (l <= mid && r <= right)
        {
            if (nums[l] > nums[r])
            {
                ret[index[l]] += right - r + 1;
                index_temp[k] = index[l];
                temp[k++] = nums[l++];
            }
            else
            {
                index_temp[k] = index[r];
                temp[k++] = nums[r++];
            }
        }
        while (l <= mid) 
        {
            index_temp[k] = index[l];
            temp[k++] = nums[l++];
        }
        while (r <= right) 
        {
            index_temp[k] = index[r];
            temp[k++] = nums[r++];
        }

        for (int i = left; i <= right; i++)
        {
            nums[i] = temp[i];
            index[i] = index_temp[i];
        }
    }
    vector<int> countSmaller(vector<int>& nums) 
    {
        int n = nums.size();
        temp.resize(n);
        index.resize(n);
        index_temp.resize(n);
        ret.resize(n);
        for (int i = 0; i < n; i++) index[i] = i;
        MergeSort(nums, 0, n - 1);
        return ret;
    }
};

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

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

相关文章

JAVA毕业设计171—基于Java+Springboot+vue3+小程序的宠物店小程序系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue3小程序的宠物店小程序系统(源代码数据库)171 一、系统介绍 本项目前后端分离(可以改为ssm版本)&#xff0c;分为用户、店员、管理员三种角色 1、用户&…

存储课程学习笔记1_访问scsi磁盘读写测试(struct sg_io_hdr,ioctl,mmap)

创建虚拟机时&#xff0c;可以选择SCSI,STAT,NVME不同类型的磁盘。 0&#xff1a;总结 》了解内核提供的访问scsi的结构和方法 &#xff08;主要是sg_io_hdr_t 结构体和ioctl函数&#xff09;。 》需要读scsi协议文档&#xff0c;了解相关指令&#xff0c;只演示了16字节固定…

华为eNSP :WLAN的配置

一、WLAN的知识点&#xff1a; VLAN配置&#xff1a; VLAN&#xff1a;可以想象成一个大房子&#xff08;网络&#xff09;里划分的不同房间&#xff08;VLAN&#xff09;。每个房间可以有自己的功能&#xff0c;比如一个用于睡觉&#xff08;管理&#xff09;&#xff0c;另一…

软件工程知识点总结(5):详细设计

面向对象详细设计举例&#xff1a;接口描述、算法描述、数据描述 类的详细描述&#xff0c;内含数据、 方法及方法的参数返回值 public class User { private String userId; private String userName; private String password; private int type; public User(String userId…

基于APISIX实现API网关案例分享

一、APISIX介绍 1、定义 Apache APISIX 是一个动态、实时、高性能的云原生 API 网关。它构建于 NGINX + ngx_lua 的技术基础之上,充分利用了 LuaJIT 所提供的强大性能。 2、软件架构 2.1、架构图 APISIX 主要分为两个部分: APISIX 核心:包括 Lua 插件、多语言插件运行时…

ICM20948 DMP代码详解(12)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;11&#xff09; 上一回开始解析icm20948_sensor_setup函数的第2段代码也即inv_icm20948_init_matrix函数&#xff1a; /* Setup accel and gyro mounting matrix and associated angle for current board */inv_icm20…

前端技术(七)——less 教程

一、less简介 1. less是什么&#xff1f; less是一种动态样式语言&#xff0c;属于css预处理器的范畴&#xff0c;它扩展了CSS语言&#xff0c;增加了变量、Mixin、函数等特性&#xff0c;使CSS 更易维护和扩展LESS 既可以在 客户端 上运行 &#xff0c;也可以借助Node.js在服…

关于武汉芯景科技有限公司的IIC缓冲器芯片XJ4307开发指南(兼容LTC4307)

一、芯片引脚介绍 1.芯片引脚 2.引脚描述 二、系统结构图 三、功能描述 1.总线超时&#xff0c;自动断开连接 当 SDAOUT 或 SCLOUT 为低电平时&#xff0c;将启动内部定时器。定时器仅在相应输入变为高电平时重置。如果在 30ms &#xff08;典型值&#xff09; 内没有变为高…

社交媒体的未来:Facebook如何通过AI技术引领潮流

在数字化时代的浪潮中&#xff0c;社交媒体平台不断演变&#xff0c;以适应用户需求和技术发展的变化。作为全球领先的社交媒体平台&#xff0c;Facebook在这一进程中扮演了重要角色。尤其是人工智能&#xff08;AI&#xff09;技术的应用&#xff0c;正在深刻地改变Facebook的…

Docker零基础入门

参考课程https://www.bilibili.com/video/BV1VC4y177re/?vd_source=b15169a302bee35f484245aecc69d4dd 参考书籍Docker 实践 - 面向 AI 开发人员的 Docker 实践 (dockerpractice.readthedocs.io) 1. 什么是Docker 1.1. Docker起源 随着计算机的发展,计算机上已经可以运行多…

Stable Diffusion绘画 | ControlNet应用-Inpaint(局部重绘):更完美的重绘

Inpaint(局部重绘) 相当于小号的AI版PS&#xff0c;不但可以进行局部画面的修改&#xff0c;还可以去除背景中多余的内容&#xff0c;或者是四周画面内容的扩充。 预处理器说明 Inpaint_Global_Harmonious&#xff1a;重绘-全局融合算法&#xff0c;会对整个图片的画面和色调…

【无标题】SAM(Segment Anything Model)

1.SAM是什么&#xff1f; SAM是基于NLP的一个基础模型&#xff0c;专注于提示分割任务&#xff0c;使用提升工程来适应不同的下游分割任务。 2.SAM有什么用&#xff1f; 1&#xff09;SAM 可以通过简单地单击或交互选择要包含或排除在对象中的点来分割对象。还可以通过使用多边…

成都爱尔综合眼病科李晓峰主任解析空调续命,干眼别忍!

高温酷暑&#xff0c;命都是空调给的。 凉风一直吹&#xff0c;根本不敢停。 热到大汗淋漓&#xff0c;身体缺水&#xff0c;眼睛也是。 屋外闷热湿度不低&#xff0c;屋内空调一开湿度“骤降”不够用。 房间被“除湿”&#xff0c;眼睛也不例外。 长时间吹空调&#xff0c…

基于C++实现(控制台)模拟网上购书订单管理系统

模拟网上购书订单管理系统&#xff08;大一小学期C大作业&#xff09; 一、任务 1. 基础任务 建立继承了Buyer类的三个子类作为顾客的三种类型&#xff0c;用于管理顾客对象&#xff1b;建立Book类&#xff0c;管理书本对象&#xff1b;根据不同类型的顾客&#xff0c;计算出…

全球主要指数年度收益率汇总

1 美国 1.1 道琼斯工业平均指数 DJIA 1.2 纳斯达克综合指数 IXIC 1.3 纳斯达克100指数 NDX 1.4 标准普尔500 INX 2 中国 2.1 国债指数 000021 2.2 上证综指 000001 2.3 深证成指 399001 2.4 创业板 399006 2.5 中小100 399005 2.6 上证50 000016 3 香港

智能可视耳勺怎么用?智能可视耳勺使用方法!

随着科技的进步&#xff0c;有很多人摒弃了传统挖耳勺&#xff0c;选择更加高效直观的智能可视耳勺&#xff0c;这是因为智能可视耳勺能更加直观地看到耳朵的内部&#xff0c;让掏耳过程清晰明了&#xff0c;精准掏出耳垢。 但市场有的智能可视耳勺鱼龙混杂&#xff0c;很多人在…

【解决】vue 弹窗后面页面可以滚动问题

做web端项目过程中&#xff0c;发现点击弹窗后&#xff0c;弹窗后面的页面还可以滚动。 复现如下&#xff1a; 【方法1】 step1&#xff1a;在弹框页面使用 mousewheel.prevent <divv-show"workShowMenu"mousewheel.prevent>// TO DO...弹框内容 </div&…

C盘清理 拯救你的C盘!C盘从此不再爆满~!

C盘清理&#xff0c;拯救你的C盘&#xff01;C盘从此不再爆满~&#xff01;C盘爆满是许多人经常遇到的问题&#xff0c;它可能导致系统运行缓慢甚至崩溃&#xff0c;对于这种情况&#xff0c;我们要从根源触发&#xff0c;彻底的清理干净C盘垃圾。 一般的C盘清理有下面几种方法…

AI跟踪报道第55期-新加坡内哥谈技术-本周AI新闻: GPT NEXT (x100倍)即将在2024推出

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

[概率论] 随机变量的分布函数 (一)

文章目录 1.随机变量的分布函数2.离散型随机变量的分布函数3.连续性随机变量的分布函数 1.随机变量的分布函数 设X XX是一个随机变量&#xff0c;x xx是任意实数&#xff0c;则函数 几何表示 性质&#xff08;一个函数是分布函数的充要条件&#xff09; 2.离散型随机变量的分布…