优选算法——分治(归并)

1. 归并排序

题目链接:912. 排序数组 - 力扣(LeetCode)

题目展示

题目分析:这里我们直接来实现归并排序即可;

代码实现

class Solution 
{
    vector<int> tmp;//在全局创建辅助数组,提高效率
public:
    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)>>1;
        //[left,mid][mid+1,right]
        //把左右区间进行排序
        mergesort(nums,left,mid);
        mergesort(nums,mid+1,right);
        //合并两个有序数组
        int cur1=left;
        int cur2=mid+1;
        int 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];
        }
    }
};

2. 交易逆序对的总数

题目链接LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

题目展示

题目分析:本题要求我们找出逆序对的数目,暴力解法肯定会超时的,所以我们需要利用归并排序的思想来解决。

大家可以看上图,其实就是归并排序的一个总过程,我们先去左区间找找,再去右区间找找,最后一左一右去找逆序对;上面有两种策略,其实本质是一样的。

代码实现

class Solution 
{
    int tmp[50010];
public:
    int reversePairs(vector<int>& record) 
    {
        return mergesort(record,0,record.size()-1);
    }
    int mergesort(vector<int>& nums,int left,int right)
    {
        if(left>=right)
        {
            return 0;
        }
        int ret=0;
        //1.找中间点
        int mid=(left+right)>>1;
        //2.左边的个数+排序+右边的个数+排序
        ret+=mergesort(nums,left,mid);
        ret+=mergesort(nums,mid+1,right);
        //3.一左一右的个数
        int cur1=left;
        int cur2=mid+1;
        int i=0;
        while(cur1<=mid&&cur2<=right)
        {
            if(nums[cur1]<=nums[cur2])
            {
                tmp[i++]=nums[cur1++];
            }
            else
            {
                ret += mid - cur1 + 1;
                tmp[i++]=nums[cur2++];
            }
        }
        //4. 处理一下排序
        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-left];
        }
        return ret;
    }
};

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

题目链接315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)

题目展示

题目分析:本题与上一题类似,需要用到上面提到的“策略二”来解决,具体大家来看下图。

本题的关键在于我们需要记录原始下标,最终返回的是数组,在操作nums数组的时候,同时操作index数组,让他们“绑定”起来,这样我们就可以找到正确的位置。

代码实现

class Solution 
{
    vector<int> ret;
    vector<int> index;//记录nums中当前元素的原始下标
    int tmpNums[500010];
    int tmpIndex[500010];

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;
        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 i=left;i<=right;i++)
        {
            nums[i]=tmpNums[i-left];
            index[i]=tmpIndex[i-left];
        }
    }
};

4. 翻转对

题目链接493. 翻转对 - 力扣(LeetCode)

题目展示

题目分析:本题其实和第二题类似,但是有一些变化;

大家可以看到,我们要在合并两个有序数组前,要先计算翻转对的数量,大家一定要结合上面的图来理解。 

代码实现

class Solution 
{
    int tmp[50010];
public:
    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)>>1; 
        //计算左右两侧翻转对
        ret+=mergesort(nums,left,mid);
        ret+=mergesort(nums,mid+1,right);
        //先计算翻转对的数量
        int cur1=left;
        int cur2=mid+1;
        int i=0;
        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 i=left;i<=right;i++)
        {
            nums[i]=tmp[i-left];
        }
        return ret;
    }
};

5. 总结

本篇博客为大家介绍了分治专题的另一部分内容——归并,大家不仅需要掌握归并排序的写法,还要会利用归并排序的思想去解决一些问题,最后,希望本文可以为大家带来帮助,感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java从入门到工作1 - 语法

1.1、注解 注解困扰了我很长时间&#xff0c;看了一堆概念。要理解注解&#xff0c;首先得理解两个概念元数据和反射机制 元数据是关于数据的数据。它提供了关于其他数据的信息或描述。例如&#xff0c;在数据库中&#xff0c;记录的结构&#xff08;字段类型、字段名称等&am…

MySQL其五,索引详解,逻辑架构,SQL优化等概念

目录 一、索引 1、索引的概念 2、索引的优缺点 3、添加索引的原则 4、索引的分类 5、索引如何使用 6、存储过程讲解 7、测试索引的效率 7、索引的数据结构 8、覆盖索引&#xff08;SQL优化的点&#xff09; 9、最佳左前缀法则&#xff08;SQL优化的点&#xff09; 二…

简单的go写的websocket协议 im 聊天 服务,流程简单清晰,采用golang编写,flutter im客户端。免费开源哈,随意用

mini-im 1、说明&#xff1a; 项目地址&#xff1a;https://github.com/haomiao33/minim 1.1、项目介绍&#xff1a; 简单的go写的im服务&#xff0c;流程简单清晰,大部分接口使用的是http&#xff0c;方便流程控制。login服务目前只是用来做服务端推送消息通知到客户端。本…

多音轨视频使用FFmpeg删除不要音轨方法

近期给孩子找宫崎骏动画&#xff0c;但是有很多是多音轨视频但是默认的都是日语&#xff0c;电视上看没办法所以只能下载后删除音轨文件只保留中文。 方法分两步&#xff0c;先安装FFmpeg在转文件即可。 第一步FFmpeg安装 FFmpeg是一个开源项目&#xff0c;包含了处理视频的…

GitHub企业版:AWS CodeCommit迁移的最佳路径与技术优势

此前&#xff0c;亚马逊网路服务&#xff08;AWS&#xff09;宣布&#xff0c;自2024年7月25日起&#xff0c;AWS CodeCommit不再接受新客户。虽然现有客户可以继续使用该服务&#xff0c;且其安全性、可用性和性能将得到维护&#xff0c;但AWS将不再推出新功能或接受新用户。 …

龙旗科技社招入职测评:言语理解材料计算图形推理真题北森题库考什么?

龙旗科技社招入职测评北森题库主要考察以下几个方面&#xff1a; 1. **言语逻辑**&#xff1a;这部分的考试时间是10分钟&#xff0c;需要完成10道题目。每题的作答时间被限定为60秒&#xff0c;一旦提交后无法返回修改。题目类型包括总结中心思想、选词填空和推理文章意思。考…

并发编程中数据的可见性

一、什么是并发编程的可见性&#xff1f; 在并发编程中&#xff0c;“可见性”是指一个线程对共享变量的修改是否能被其他线程及时看到的特性。 二、不可见情况的测试 现在设置成员属性flagtrue&#xff0c;如果flagtrue则t1线程一直死循环执行任务&#xff0c;main线程设置fl…

不配置python环境,直接用PyCharm就可以?

有的伙伴可能遇到不安装python环境只安装pycharm也可以进行运行代码。 所以自认为是不需要解释器就可以运行&#xff1f; 这个是不现实的&#xff0c;有很多伙伴可能是安装了Pycharm&#xff0c;但Pycharm看你电脑上没有解释器&#xff0c;所以在安装的时候给你默认安装在C盘…

C语音顺序表专题及应用

数据结构引进 0数据结构相关概念 0.1什么是数据结构 数据结构是由“数据”和“结构”两词组合而来。 什么是数据&#xff1f;常见的数值1、2、3、4…、教务系统⾥保存的用户信息&#xff08;姓名、性别、年龄、学历等等&#xff09;、网页肉眼可以看到的信息&#xff08;⽂字…

单元测试总结

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Hello&#xff01;大家好&#xff0c;我是一个专注于分享软件测试干货的测试开发。 对于软件测试&#xff0c;我们先按照开发阶段来进行划分&#xff0c;将软件测…

immaculate C# DragDrop 注册失败 解决 C#窗口程序如何看控制台打印的日志

C# DragDrop 注册失败 System.InvalidOperationExceptionHResult0x80131509MessageDragDrop 注册失败。SourceSystem.Windows.FormsStackTrace:在 System.Windows.Forms.Control.SetAcceptDrops(Boolean accept)在 System.Windows.Forms.Control.OnHandleCreated(EventArgs e)…

怎样衡量电阻负载的好坏

电阻负载的好坏通常通过以下几种方法来衡量&#xff1a; 1. 测量电阻值&#xff1a;最直接的方法是使用万用表来测量电阻负载的电阻值。将万用表设置在适当的电阻档位&#xff0c;然后将测试笔连接到电阻负载的两个引脚上。如果电阻负载是好的&#xff0c;那么万用表应该显示一…

酒蒙子骰子小程序系统

酒蒙子流量变现小程序小游戏 后端tp8 前端uniapp 会员变现 分销推广 流量主 …

Spring Boot 3.x:自动配置类加载机制的变化

随着 Spring Boot 3.x 版本的发布&#xff0c;Spring Boot 引入了一些关键的变更。其中最重要的一项变更是 自动配置类的加载机制。在之前的版本中&#xff0c;Spring Boot 使用 spring.factories 文件来管理自动配置类的加载。然而&#xff0c;在 Spring Boot 3.x 中&#xff…

网络安全学习路线

《网络安全自学教程》 网络安全这几年改成了网络空间安全&#xff0c;因为网络空间也是国家主权之一&#xff0c;网络空间不安全&#xff0c;你就要在别人眼皮子底下裸奔&#xff0c;当然&#xff0c;非洲的小伙伴就不用担心受到威胁&#xff0c;毕竟他们连网都没有。 网络安全…

【Linux网络编程】第十一弹---HTTP协议全解析:从请求响应到方法与Header的详尽指南

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、HTTP 协议 1.1、认识 URL ​1.2、urlencode 和 urldecode 1.3、HTTP 协议请求与响应格式 1.3.1、代码…

从 Router 到 Navigation:HarmonyOS 路由框架的全面升级与迁移指南

在本教程中&#xff0c;我们深入探讨了 Router 和 Navigation 在 HarmonyOS 中的用法差异及如何从 Router 切换到 Navigation 的方法。重点涵盖了页面跳转、转场动画、生命周期管理以及跨包路由的实现。 页面结构对比 Router 页面结构 每个页面需要使用 Entry 注解。 页面需要…

账号下的用户列表表格分析

好的&#xff0c;这是您提供的 el-table 组件中所有列的字段信息&#xff0c;以表格形式展示&#xff1a; 列标题 (label)字段属性 (prop)对齐方式 (align)宽度 (width)是否可排序 (sortable)说明IDidcenter100否管理员的唯一标识符头像avatarcenter90否管理员的头像 URL 或路…

luckysheet与superslide冲突解决

[现象]控制台报错、界面无法操作 $是jquery。查看源码&#xff0c;发现mousewheel方法来自插件mousewheel&#xff0c;luckysheet初始应该会将mousewheel挂载在jquery上。 在控制台打印jquery取dom及其方法&#xff0c;结果如下&#xff1a; 不存在mousewheel方法&#xff0c…

windows使用python写的YOLO来实现目标识别

使用labelImg标注&#xff0c;YOLO进行目标训练 一、labelImg工具下载及使用1、下载labelImg&#xff08;目标标注工具[【点我下载】](https://github.com/HumanSignal/labelImg)&#xff09;2、使用labelImg 二、下载及使用YOLO1、下载及使用ultralytics&#xff08;volo[点击…