算法8--归并

news2025/2/3 22:30:26

目录

  • 原理
  • 经典例题
    • [912. 排序数组](https://leetcode.cn/problems/sort-an-array/description/)
    • [LCR 170. 交易逆序对的总数](https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/description/)
    • 计算右侧小于当前元素的个数
    • [493. 翻转对](https://leetcode.cn/problems/reverse-pairs/description/)

原理

归并算法的原理可以参考归并排序,归并排序算法不仅仅是使用该算法对数据进行排序,重要的是在归并的过程中解决某些问题,从而使一些原本时间复杂度较高的问题降到O(n*log2n)。

经典例题

912. 排序数组

给你一个整数数组 nums,请你将该数组升序排列。
你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

这里可以使用归并排序解决:

class Solution {
public:
    void MySort(vector<int>& nums,int left,int right){
        if(left>=right){
            return;
        }
        int mid=(left+right)/2;
        MySort(nums,left,mid);
        MySort(nums,mid+1,right);
        int pos1=left;
        int pos2=mid+1;
        int end1=mid;
        int end2=right;
        vector<int> tmp;
        while(pos1<=end1&&pos2<=end2){
            if(nums[pos1]<nums[pos2]){
                tmp.push_back(nums[pos1]);
                ++pos1;
            }
            else if(nums[pos1]>nums[pos2]){
                tmp.push_back(nums[pos2]);
                ++pos2;
            }
            else{
                tmp.push_back(nums[pos1]);
                tmp.push_back(nums[pos2]);
                ++pos1;
                ++pos2;
            }
        }
        while(pos1<=end1){
            tmp.push_back(nums[pos1]);
            ++pos1;
        }
        while(pos2<=end2){
            tmp.push_back(nums[pos2]);
            ++pos2;
        }

        int i=left;
        for(auto e:tmp){
            nums[i++]=e;
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        if(0==nums.size()){
            return nums;
        }
        MySort(nums,0,(int)nums.size()-1);
        return nums;
    }
};

LCR 170. 交易逆序对的总数

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

排降序,归并过程中计算逆序对

class Solution {
public:
    int GetAnswer(vector<int>& record,int left,int right){
        if(left>=right){
            return 0;
        }
        int mid=(left+right)/2;
        int count=GetAnswer(record,left,mid)+GetAnswer(record,mid+1,right);
        int pos1=left;
        int pos2=mid+1;
        int end1=mid;
        int end2=right;
        vector<int> tmp;
        while(pos1<=end1&&pos2<=end2){
            if(record[pos1]<record[pos2]){
                tmp.push_back(record[pos2++]);
            }
            else if(record[pos1]>record[pos2]){
                tmp.push_back(record[pos1++]);
                count+=end2-pos2+1;
            }
            else{
                tmp.push_back(record[pos2++]);
            }
        }
        while(pos1<=end1){
            tmp.push_back(record[pos1++]);
        }
        while(pos2<=end2){
            tmp.push_back(record[pos2++]);
        }
        for(auto e:tmp){
            record[left++]=e;
        }

        return count;
    }
    int reversePairs(vector<int>& record) {
        if(0==record.size()){
            return 0;
        }
        return GetAnswer(record,0,record.size()-1);
    }
};

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

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

只需每个元素都绑定好数组下标,再进行归并排序即可,同时为了避免数组的开辟释放,可以提前开好足够的数组空间直接在该数组上操作即可,从而得到一定的优化。

class Solution {
public:
    void GetAnswer(vector<vector<int>>&nums,int left,int right){
        if(left>=right){
            return;
        }
        int mid=(left+right)/2;
        GetAnswer(nums,left,mid);
        GetAnswer(nums,mid+1,right);
        if(nums[left][0]==nums[mid][0]&&nums[mid][0]==nums[mid+1][0]&&nums[mid+1][0]==nums[right][0]){
            return;
        }
        int pos1=left;
        int pos2=mid+1;
        int end1=mid;
        int end2=right;
        vector<vector<int>> tmp;
        tmp.reserve(right-left+1);
        while(pos1<=end1&&pos2<=end2){
            if(nums[pos1][0]<nums[pos2][0]){
                tmp.push_back(nums[pos2++]);
            }
            else if(nums[pos1][0]>nums[pos2][0]){
                nums[pos1][1]+=end2-pos2+1;
                tmp.push_back(nums[pos1++]);
            }else{
                tmp.push_back(nums[pos2++]);
            }
        }

        while(pos1<=end1){
            tmp.push_back(nums[pos1++]);
        }

        for(auto& e:tmp){
            nums[left++]=e;
        }
    }

    vector<int> countSmaller(vector<int>& nums) {
        vector<vector<int>> tmp(nums.size(),vector<int>(3,0));
        int i=0;
        for(;i<nums.size();++i){
            tmp[i][0]=nums[i];
            tmp[i][2]=i;
        }
        GetAnswer(tmp,0,nums.size()-1);
        vector<int> ans(nums.size(),0);
        for(auto &e:tmp){
            ans[e[2]]=e[1];
        }
        return ans;
    }
};

493. 翻转对

给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。

排降序归并
解法一:归并过程中,如果:

  • nums [left]>2*nums[right]:left移入tmp1中,计算翻转对,++left
  • nums[right] <= nums [left] <= 2*nums[right]:right移入tmp2中,++right
  • nums [left] < nums[right]:right移入tmp1中,++right

解法二:
对左右两个部分,先计算完所有翻转对,再合并

class Solution {
public:
        int GetAnswer(vector<int>& record, int left, int right) {
        if (left >= right) {
            return 0;
        }
        int mid = (left + right) / 2;
        int count = GetAnswer(record, left, mid) + GetAnswer(record, mid + 1, right);
        int pos1 = left;
        int pos2 = mid + 1;
        int end1 = mid;
        int end2 = right;
        vector<int> tmp1;
        vector<int> tmp2;

        while (pos1 <= end1 && pos2 <= end2) {
            if (record[pos1] < record[pos2]) {
                if((long long int)record[pos1] >2* (long long int)record[pos2]){
                    count += end2 - pos2 + 1;
                    tmp2.push_back(record[pos1++]);
                }else{
                    tmp1.push_back(record[pos2++]);
                }
            }
            else {
                if((long long int)record[pos1] >2* (long long int)record[pos2]){
                    count += end2 - pos2 + 1;
                    tmp1.push_back(record[pos1++]);
                }else{
                    tmp2.push_back(record[pos2++]);
                }
            }
        }
        while (pos1 <= end1) {
            tmp1.push_back(record[pos1++]);
        }
        while (pos2 <= end2) {
            tmp1.push_back(record[pos2++]);
        }
        vector<int> tmp;
        for(pos1=0,pos2=0;pos1<tmp1.size()&&pos2<tmp2.size();){
            if(tmp1[pos1]>tmp2[pos2]){
                tmp.push_back(tmp1[pos1++]);
            }else if(tmp1[pos1]<tmp2[pos2]){
                tmp.push_back(tmp2[pos2++]);
            }else{
                tmp.push_back(tmp1[pos1++]);
                tmp.push_back(tmp2[pos2++]);
            }
        }
        while(pos1<tmp1.size()){
            tmp.push_back(tmp1[pos1++]);
        }
        while(pos2<tmp2.size()){
            tmp.push_back(tmp2[pos2++]);
        }
        for (auto e : tmp) {
            record[left++] = e;
        }

        return count;
    }

    int reversePairs(vector<int>& nums) {
        return GetAnswer(nums,0,nums.size()-1);
    }
};

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

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

相关文章

8.攻防世界Web_php_wrong_nginx_config

进入题目页面如下 尝试弱口令密码登录 一直显示网站建设中&#xff0c;尝试无果&#xff0c;查看源码也没有什么特别漏洞存在 用Kali中的dirsearch扫描根目录试试 命令&#xff1a; dirsearch -u http://61.147.171.105:53736/ -e* 登录文件便是刚才登录的界面打开robots.txt…

基于Langchain-Chatchat + ChatGLM 本地部署知识库

一、相关环境 参考链接: Github:https://github.com/chatchat-space/Langchain-Chatchat Langchain-chatchat版本&#xff1a;v0.3.1 安装环境&#xff1a;Ubuntu&#xff1a;22.04&#xff0c;CUDA&#xff1a;12.1 二、搭建过程 2.1 环境配置 2.1.1 创建chatchat虚拟环…

grpc 和 http 的区别---二进制vsJSON编码

gRPC 和 HTTP 是两种广泛使用的通信协议&#xff0c;各自适用于不同的场景。以下是它们的详细对比与优势分析&#xff1a; 一、核心特性对比 特性gRPCHTTP协议基础基于 HTTP/2基于 HTTP/1.1 或 HTTP/2数据格式默认使用 Protobuf&#xff08;二进制&#xff09;通常使用 JSON/…

Cypher入门

文章目录 Cypher入门创建数据查询数据matchoptional matchwhere分页with 更新数据删除数据实例&#xff1a;好友推荐 Cypher入门 Cypher是Neo4j的查询语言。 创建数据 在Neo4j中使用create命令创建节点、关系、属性数据。 create (n {name:$value}) return n //创建节点&am…

深度学习深度解析:从基础到前沿

引言 深度学习作为人工智能的一个重要分支&#xff0c;通过模拟人脑的神经网络结构来进行数据分析和模式识别。它在图像识别、自然语言处理、语音识别等领域取得了显著成果。本文将深入探讨深度学习的基础知识、主要模型架构以及当前的研究热点和发展趋势。 基础概念与数学原理…

如何使用SliverGrid组件

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverList组件相关的内容&#xff0c;本章回中将介绍SliverGrid组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverGrid组件是一种网格类组件&#xff0c;主要用来…

K8S集群架构及主机准备

本次集群部署主机分布K8S集群主机配置主机静态IP设置主机名解析ipvs管理工具安装及模块加载主机系统升级主机间免密登录配置主机基础配置完后最好做个快照备份 2台负载均衡器 Haproxy高可用keepalived3台k8s master节点5台工作节点(至少2及以上)本次集群部署主机分布 K8S集群主…

012-51单片机CLD1602显示万年历+闹钟+农历+整点报时

1. 硬件设计 硬件是我自己设计的一个通用的51单片机开发平台&#xff0c;可以根据需要自行焊接模块&#xff0c;这是用立创EDA画的一个双层PCB板&#xff0c;所以模块都是插针式&#xff0c;不是表贴的。电路原理图在文末的链接里&#xff0c;PCB图暂时不选择开源。 B站上传的…

数据分析系列--[11] RapidMiner,K-Means聚类分析(含数据集)

一、数据集 二、导入数据 三、K-Means聚类 数据说明:提供一组数据,含体重、胆固醇、性别。 分析目标:找到这组数据中需要治疗的群体供后续使用。 一、数据集 点击下载数据集 二、导入数据 三、K-Means聚类 Ending, congratulations, youre done.

深度学习查漏补缺:1.梯度消失、梯度爆炸和残差块

一、梯度消失 梯度消失的根本原因在于 激活函数的性质和链式法则的计算&#xff1a; 激活函数的导数很小&#xff1a; 常见的激活函数&#xff08;例如 Sigmoid 和 Tanh&#xff09;在输入较大或较小时&#xff0c;输出趋于饱和&#xff08;Sigmoid 的输出趋于 0 或 1&#xf…

于动态规划的启幕之章,借 C++ 笔触绘就算法新篇

注意&#xff1a;代码由易到难 P1216 [IOI 1994] 数字三角形 Number Triangles 题目链接&#xff1a;[IOI 1994] 数字三角形 Number Triangles - 洛谷 题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每…

基于开源2 + 1链动模式AI智能名片S2B2C商城小程序的内容创作与传播效能探究

摘要&#xff1a;本文围绕开源2 1链动模式AI智能名片S2B2C商城小程序&#xff0c;深入探讨在其应用场景下内容创作与传播效果的关键要素——转发数与转化率。通过剖析如何创作引发用户共鸣、提升用户信任的内容&#xff0c;阐明深度思考内容本质对于实现有效传播的重要性&…

深度学习之“线性代数”

线性代数在深度学习中是解决多维数学对象计算问题的核心工具。这些数学对象包括标量、向量、矩阵和张量&#xff0c;借助它们可以高效地对数据进行操作和建模。以下将详细介绍这些数学对象及其在深度学习中的典型用途。 数学对象概述 标量 标量是最简单的数学对象&#xff0…

SpringBoot的配置(配置文件、加载顺序、配置原理)

文章目录 SpringBoot的配置(配置文件、加载顺序、配置原理)一、引言二、配置文件1、配置文件的类型1.1、配置文件的使用 2、多环境配置 三、加载顺序四、配置原理五、使用示例1、配置文件2、配置类3、控制器 六、总结 SpringBoot的配置(配置文件、加载顺序、配置原理) 一、引言…

CVE-2023-38831 漏洞复现:win10 压缩包挂马攻击剖析

目录 前言 漏洞介绍 漏洞原理 产生条件 影响范围 防御措施 复现步骤 环境准备 具体操作 前言 在网络安全这片没有硝烟的战场上&#xff0c;新型漏洞如同隐匿的暗箭&#xff0c;时刻威胁着我们的数字生活。其中&#xff0c;CVE - 2023 - 38831 这个关联 Win10 压缩包挂…

Clion开发STM32时使用stlink下载程序与Debug调试

一、下载程序 先创建一个文件夹&#xff1a; 命名&#xff1a;stlink.cfg 写入以下代码: # choose st-link/j-link/dap-link etc. #adapter driver cmsis-dap #transport select swdsource [find interface/stlink.cfg]transport select hla_swdsource [find target/stm32f4x.…

无人机图传模块 wfb-ng openipc-fpv,4G

openipc 的定位是为各种模块提供底层的驱动和linux最小系统&#xff0c;openipc 是采用buildroot系统编译而成&#xff0c;因此二次开发能力有点麻烦。为啥openipc 会用于无人机图传呢&#xff1f;因为openipc可以将现有的网络摄像头ip-camera模块直接利用起来&#xff0c;从而…

C语言 --- 分支

C语言 --- 分支 语句分支语句含义if...else语句单分支if语句语法形式 双分支 if-else 语句语法形式 悬空else含义问题描述 多分支 if-else 语句语法形式 switch...case语句含义语法形式 总结 &#x1f4bb;作者简介&#xff1a;曾与你一样迷茫&#xff0c;现以经验助你入门 C 语…

低代码系统-产品架构案例介绍、炎黄盈动-易鲸云(十二)

易鲸云作为炎黄盈动新推出的产品&#xff0c;在定位上为低零代码产品。 开发层 表单引擎 表单设计器&#xff0c;包括设计和渲染 流程引擎 流程设计&#xff0c;包括设计和渲染&#xff0c;需要说明的是&#xff1a;采用国际标准BPMN2.0&#xff0c;可以全球通用 视图引擎 视图…

自制虚拟机(C/C++)(三、做成标准GUI Windows软件,扩展指令集,直接支持img软盘)

开源地址:VMwork 要使终端不弹出&#xff0c; #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") 还要实现jmp near 0x01类似的 本次的main.cpp #include <graphics.h> #include <conio.h> #include <windows.h> #includ…