【分治思想】归并排序 与 逆序对

归并排序

归并排序是一种分治算法,怎么分,怎么治?

  • 分:通过递归不断把数组分成两半,直到每个子数组只剩 1 个元素(天然有序)
  • 治:把两个已经排好序的子数组合并成一个有序数组。

把问题分解为简单子问题,就体现在每个数组只剩一个元素时,那就天然有序了。

模板题

P1177 【模板】排序
在这里插入图片描述

归并排序代码实现

#include<iostream>using namespace std;const int N = 1e5 + 10;int n, a[N], tmp[N]; //a存数据,tmp辅助归并排序时合并两个数组 void merge_sort(int left, int right)
{if(left >= right) return; //left == right只有一个元素,有序,返回 //1.数组一分为二 int mid = (left + right) / 2;//2.将左右数组都排好序 merge_sort(left, mid);merge_sort(mid + 1, right);//3.合并左右有序数组到tmp中 int cur1 = left, cur2 = mid + 1, i = left; //i帮助写入临时数组 while(cur1 <= mid && cur2 <= right){if(a[cur1] <= a[cur2]) tmp[i++] = a[cur1++];else tmp[i++] = a[cur2++];}while(cur1 <= mid) tmp[i++] = a[cur1++];while(cur2 <= right) tmp[i++] = a[cur2++];//4.将tmp中的[left,right]区间转移到a的[left,right]区间 for(int j=left;j<=right;j++) a[j] = tmp[j]; //最容易错的一步,要知道在merge_sort函数中,我们是对[left, right]区间进行排序而不是[0, n] 
}int main()
{cin >> n;for(int i=1;i<=n;i++) cin >> a[i];merge_sort(1,n);for(int i=1;i<=n;i++) cout << a[i] << " ";return 0;
}

时间复杂度

不断地将数组一分为二,直到只剩下一个元素为止,时间复杂度为 logn;
将 tmp 数组复制到 a 数组,时间复杂度为 n。
总的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

逆序对

什么是逆序对?

逆序对(Inversion)是指在一个序列中,如果前面的数比后面的数大,那么这两个数就构成一个逆序对。

逆序对和排序的关系

  • 逆序对的数量衡量了序列的无序程度:逆序对越多,序列越乱;逆序对越少,序列越接近有序。
  • 排序的本质就是消除逆序对

例题

P1908 逆序对
在这里插入图片描述

分析

首先我们可以想到两层for循环暴力统计逆序对个数,但是会超时。

我们可以尝试一下分治的思想,在原数组中找逆序对,相当于先将数组一分为二,在左半边数组找逆序对,在右半边数组找逆序对,再一左一右找逆序对,所有的逆序对数量加起来就是原数组的逆序对数量。

于是我们得到了这样两个数组,分别对左右求逆序对,这咋求???这还不是要两层for循环挨个遍历统计逆序对吗,这算上二分数组的时间复杂度,现在总时间复杂度干到了 O ( n 2 l o g n ) O(n^2logn) O(n2logn),这能对吗?
请添加图片描述
但是当左边这个数组和右边这个数组分别有序的时候,再统计逆序对个数就非常方便了。我们选择一个元素在左边数组,另一个元素在右边数组的逆序对,统计逻辑如下:

请添加图片描述
我们可以发现,这与归并排序中合并有序数组的流程是一致的。

但是这里就有一个问题:对左边数组和右边数组分别排序的话,是否会影响逆序对的统计呢?
不会,因为在统计一左一右的时候,左右数组的逆序对已经统计过了,才形成的左右这样有序的数组,统计逆序对的统计和归并排序是同时进行的。
我们仍可以从极限情况分析,当数组的长度为2时,分成左右数组,它们的长度分别为1,于是左右数组中的逆序对个数肯定为0,我们接下来统计一左一右的逆序对个数,统计完之后,这个长度为2的数组也就通过归并排序变得有序了。另一边肯定也通过这样相同的流程得到了一个长度为2的有序数组,然后对它们进行一左一右的逆序对统计,这时候再思考为什么不分别统计左右数组中的逆序对个数呢?因为已经统计过了,它们就是在一左一右合并的过程中统计的。

代码

#include<iostream>using namespace std; typedef long long LL;const int N = 5e5 + 10;int n, a[N], tmp[N];LL merge(int left, int right)
{if(left >= right) return 0;//1.一分为二int mid = (left + right) >> 1; //2.计算左右数组LL ret = 0; ret += merge(left, mid);ret += merge(mid + 1, right);//3.合并左右数组int cur1 = left, cur2 = mid + 1, i = left;while(cur1 <= mid && cur2 <= right){if(a[cur1] <= a[cur2]) tmp[i++] = a[cur1++];else{tmp[i++] = a[cur2++];ret += mid - cur1 + 1; }	} while(cur1 <= mid) tmp[i++] = a[cur1++];while(cur2 <= right) tmp[i++] = a[cur2++];for(int j=left;j<=right;j++) a[j] = tmp[j];return ret;
}int main()
{cin >> n;for(int i=1;i<=n;i++) cin >> a[i];cout << merge(1,n) << endl;	return 0;
}

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

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

相关文章

SQL参数化查询:防注入与计划缓存的双重优势

在数据库操作中&#xff0c;SQL参数化查询&#xff08;Parameterized Queries&#xff09;是一种非常有效的技术&#xff0c;它不仅可以防止SQL注入攻击&#xff0c;还可以提高数据库查询的效率&#xff0c;尤其是在与计划缓存&#xff08;Query Plan Caching&#xff09;结合使…

【你怕一E1】- 孰轻孰重如何断-组合问题的多种情形

摘要 本视频讲解了组合问题的多种情形,包括多选一、多选二、多选三以及分队问题的解题方法。首先介绍了从不同人数中选人的不同选择方式,如一百人中选一人有一百种选择。随后,详细讲解了有序思考方法在多选二问题中的应用,通过选队长的方式列举不同组合情况,并归纳出选择规…

nginx反向代理的bug

nginx反向代理的bug 问题呈现 当我们配置反向代理的时候查询error.log的时候我们发现以下的问题 2025/06/29 08:38:47 [error] 7#7: *2 open() “/usr/share/nginx/html/payed/notify” failed (2: No such file or directory), client: 192.168.98.1, server: localhost, r…

MyBatis 动态 SQL 与缓存机制深度解析

在Java持久层技术体系中&#xff0c;MyBatis凭借其灵活的SQL映射和强大的动态SQL能力&#xff0c;成为企业级应用开发的首选框架。本文从动态SQL核心语法、缓存实现原理、性能优化及面试高频问题四个维度&#xff0c;结合源码与工程实践&#xff0c;系统解析MyBatis的核心特性与…

Nuxt 3 中实现跨组件通信方式总结:使用 Pinia、Provide/Inject 或 Props

在开发复杂的 Web 应用时&#xff0c;跨组件通信是一个常见的需求。Nuxt 3 提供了多种方式来实现这一点&#xff0c;包括使用状态管理工具&#xff08;如 Pinia&#xff09;、Vue 的 provide/inject 机制以及传统的 props 传递。本文将详细介绍这三种方法&#xff0c;并通过一个…

Java ArrayList 扩容机制

一、ArrayList 简介 ArrayList 是 Java 集合框架中基于数组实现的可变长度列表&#xff0c;其核心特性是&#xff1a; 支持随机访问&#xff08;通过索引&#xff09;支持动态扩容插入/删除效率较低&#xff08;非尾部操作&#xff09; 二、底层数据结构 // JDK 11 transien…

C++面试题精讲系列之数组排序

数组排序是我们经常遇到的笔试题目&#xff0c;给大家盘一下这题到底想考察什么&#xff1f; // 考题如下 void main() {int arr[4] {26,28,24,11};// 请实现一个sortArray函数&#xff0c;对数组arr进行从小到大排序 }考点1&#xff1a;数组做函数参数如何传递参&#xff1f;…

Windows10/11 轻度优化 纯净版,12个版本!

系统介绍 镜像包均基于微软官方原版系统精心制作&#xff0c;确保系统的原汁原味与稳定性。Windows 10/11&#xff0c;都集成了最新的补丁。版本选对&#xff0c;一键安装到位&#xff0c;全自动无人值守安装模式。 系统特点 系统进行优化提供了12个系统版本集成了运行库、…

开发工具IDEA

开发工具IDEA 开发调试&#xff08;debug&#xff09;Maven配置三级目录 开发调试&#xff08;debug&#xff09; 史上最全的 IDEA Debug 调试技巧&#xff08;超详细案例&#xff09; Maven配置 idea全局Maven配置 IDEA中Maven配置详解 有些时候不要配置maven_home这些环境…

GitHub Actions与AWS OIDC实现安全的ECR/ECS自动化部署

引言 在现代云原生应用开发中,实现安全、高效的CI/CD流程至关重要。本文将详细介绍如何利用GitHub Actions和AWS OIDC(OpenID Connect)构建一个无需长期凭证的安全部署管道,将容器化应用自动部署到Amazon ECR和ECS服务。 架构概述 整个解决方案的架构包含三个主要部分:…

一、MongoDB安装-二进制安装

下载tar包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.21.tgz wget https://downloads.mongodb.com/compass/mongosh-2.5.3-linux-x64.tgz安装 解压 tar xf mongodb-linux-x86_64-rhel70-7.0.21.tgz cp mongodb-linux-x86_64-rhel70-7.0.21/bi…

学习日志03 ETF 基础数据可视化分析与简易管理系统

1 代码的选择和改进 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from ipywidgets import (AppLayout, Dropdown, Button, Output, VBox, HBox, Label, Layout, SelectMultiple,IntSlider, FloatSlider, Checkbox, Text, Select) from IPytho…

[Python] -基础篇7-新手常见Python语法错误及解决方案

Python 以其简洁明了的语法引人入胜,但对于初学者而言,仍然容易遭遇各类语法错误。本文总结了 Python 语言日常编写中最常见的语法错误类型,并提供解决方案和正确写法,帮助新手快速突破编程路上的一道道埋伏。 1. 拼写错误 (SyntaxError) 这是最基本也最常见的错误类型。…

位运算实战:数值构造终极优化

位运算优化实战&#xff1a;数值构造问题详解 今天我们将深入分析一个有趣的位运算优化问题&#xff0c;这个问题展示了如何通过巧妙的预处理和贪心算法来高效解决数值构造问题。 问题背景与定义 给定一个初始值x&#xff08;0 ≤ x ≤ m&#xff09;和一系列位运算操作&…

nosql项目:基于 Redis 哨兵模式的鲜花预订配送系统

1 鲜花预订配送系统概述 1.1 项目背景 鲜花预订系统是一个实时处理用户订单、库存管理和配送跟踪的平台。系统需要处理大量并发订单&#xff0c;实时更新鲜花库存状态&#xff0c;并跟踪配送进度。传统关系型数据库难以应对高并发的订单处理和实时库存更新需求&#xff0c;因…

中心效应:多中心临床试验的关键考量

一、中心效应的来源与影响 1.1 常见来源 1.1.1 患者异质性 中心间基线特征差异(如疾病严重度、合并症比例) 1.1.2 操作差异 给药规范(如输液速度)、随访依从性、数据记录质量 1.1.3 评估偏倚 影像学判读标准(如RECIST)、实验室检测方法(如中心实验室 vs 本地实验室) …

Redis 实现消息队列

一、为什么选择 Redis 作为消息队列&#xff1f; 在分布式系统架构中&#xff0c;消息队列是实现异步通信和解耦的核心组件。Redis 作为一个高性能的内存数据库&#xff0c;凭借其卓越的速度和丰富的数据结构&#xff0c;成为轻量级消息队列的理想选择&#xff1a; 1.1 核心优…

(3)pytest的setup/teardown

1. 简介 学过unittest的都知道里面用前置和后置setup和teardown非常好用&#xff0c;在每次用例开始前和结束后都去执行一次。 当然还有更高级一点的setupClass和teardownClass&#xff0c;需配合classmethod装饰器一起使用&#xff0c;在做selenium自动化的时候&#xff0c;它…

Starrocks存算一体和存算分离

网上整理了一下starrocks两种部署方式的区别差异性&#xff0c;个人感觉生产环境还是尽量存算分离部署&#xff0c;防止资源争夺等问题影响线上生产数据&#xff0c;虽然存算一体部署起来更方便一些 &#x1f4ca; 1. 架构设计 存算一体&#xff1a; 节点类型&#xff1a;仅包含…

多线程编程 ----线程主动退出pthread_exit与线程被动退出pthread_cancel

主动退出 pthread_exit 与 pthread_cancel 的区别 1. 核心区别 特性pthread_exitpthread_cancel调用者线程自身调用&#xff0c;主动退出。其他线程调用&#xff0c;异步请求终止目标线程。行为方式立即终止线程&#xff0c;资源需手动释放。发送取消请求&#xff0c;线程在取…