算法刷题day24:归并排序

目录

  • 引言
  • 概念
  • 一、火柴排队
  • 二、归并排序
  • 三、逆序对的数量
  • 四、小朋友排队
  • 五、超级快速排序

引言

关于这个归并排序,考察的还是挺多的,在笔试面试中会问你,或者直接让你写一个归并排序,还有竞赛中有时也会考察,不过一般都是小题,主要是考察递归和递推,看你对这个过程的理解,所以还是很重要的,加油!


概念

归并排序参考博客:归并排序
冒泡排序交换的次数就是逆序对的数量,如果要求数量可用归并排序来求解,超快速排序就是归并排序


一、火柴排队

标签:归并排序

思路:只要把 a a a b b b 中的数由小到大一一对应,这样的结果是最小的。但是不必要两个数组都排序,我们可以把 a a a 抽象成有序的,就是把 a a a 当作有序,然后让 b b b 去排成这种有序的。然后最优解就是求逆序对的数量。

题目描述:

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑i=1n(ai−bi)2其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。输入格式
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。 第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。输出格式
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。数据范围
1≤n≤105,0≤火柴高度≤231−1
输入样例:
4
2 3 1 4
3 2 1 4
输出样例:
1

示例代码:

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 100010, MOD = 99999997;int n;
int a[N], b[N], c[N], p[N];void work(int a[])
{for (int i = 1; i <= n; i ++ ) p[i] = i;sort(p + 1, p + n + 1, [&](int x, int y) {return a[x] < a[y];});for (int i = 1; i <= n; i ++ ) a[p[i]] = i;
}int merge_sort(int l, int r)
{if (l >= r) return 0;int mid = l + r >> 1;int res = (merge_sort(l, mid) + merge_sort(mid + 1, r)) % MOD;int i = l, j = mid + 1, k = 0;while (i <= mid && j <= r)if (b[i] < b[j]) p[k ++ ] = b[i ++ ];else p[k ++ ] = b[j ++ ], res = (res + mid - i + 1) % MOD;while (i <= mid) p[k ++ ] = b[i ++ ];while (j <= r) p[k ++ ] = b[j ++ ];for (i = l, j = 0; j < k; i ++, j ++ ) b[i] = p[j];return res;
}int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);work(a), work(b);for (int i = 1; i <= n; i ++ ) c[a[i]] = i;for (int i = 1; i <= n; i ++ ) b[i] = c[b[i]];printf("%d\n", merge_sort(1, n));return 0;
}

二、归并排序

标签:归并排序、模板题

思路:模板题,没啥说的

题目描述:

给定你一个长度为 n 的整数数列。请你使用归并排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式
输入共两行,第一行包含整数 n。第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整个数列。输出格式
输出共一行,包含 n 个整数,表示排好序的数列。数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int N = 1e5+10;int n;
int a[N], backup[N];void merge_sort(int l, int r)
{if(l >= r) return;int mid = l + r >> 1;merge_sort(l, mid), merge_sort(mid+1, r);int i = l, j = mid + 1, k = 0;while(i <= mid && j <= r){if(a[i] <= a[j]) backup[k++] = a[i++];else backup[k++] = a[j++];}while(i <= mid) backup[k++] = a[i++];while(j <= r) backup[k++] = a[j++];for(int i = l, j = 0; i <= r; ++i, ++j) a[i] = backup[j];
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 0; i < n; ++i) cin >> a[i];merge_sort(0, n - 1);for(int i = 0; i < n; ++i) cout << a[i] << " ";cout << endl;return 0;
}

三、逆序对的数量

标签:归并排序、模板题

思路:模板题,没啥说的

题目描述:

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。输入格式
第一行包含整数 n,表示数列的长度。第二行包含 n 个整数,表示整个数列。输出格式
输出一个整数,表示逆序对的个数。数据范围
1≤n≤100000,数列中的元素的取值范围 [1,109]。输入样例:
6
2 3 4 5 6 1
输出样例:
5

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int N = 1e5+10;int n;
int a[N], backup[N];LL merge_sort(int l, int r)
{if(l >= r) return 0;int mid = l + r >> 1;LL res = merge_sort(l, mid) + merge_sort(mid+1, r);int i = l, j = mid+1, k = 0;while(i <= mid && j <= r){if(a[i] <= a[j]) backup[k++] = a[i++];else{res += mid - i + 1;backup[k++] = a[j++];}}while(i <= mid) backup[k++] = a[i++];while(j <= r) backup[k++] = a[j++];for(int i = l, j = 0; i <= r; ++i, ++j) a[i] = backup[j];return res;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 0; i < n; ++i) cin >> a[i];LL res = merge_sort(0, n-1);cout << res << endl;return 0;
}

四、小朋友排队

标签:归并排序、树状数组

思路1: 树状数组
首先最优解交换的次数就是冒泡排序的次数 k k k ,也就是逆序对的个数 k k k 了,我们只要知道每一个小朋友的交换次数,就可以用公式计算出来不高兴程度并算出总和。每个小朋友的交换次数等于,在这之前的大的个数加上后面小的个数,因为这也就相当于两倍逆序对的个数,这就说明这种做法就是最优的。我们可以用树状数组来模拟,用下标来表示高度,元素代表该高度的人数,然后可以从前往后插入,求第 i i i 个人的高度 h [ i ] h[i] h[i] 前面有多少人比他高(用前缀和思想),同理可以从后往前遍历,就能知道第 i i i 号人的高度 h [ i ] h[i] h[i] 后面有多少人比他低,就可以得知 s u m [ i ] sum[i] sum[i] ,然后就是一个等差数列用公式就每个人之和即可。

题目描述:

示例代码1: 树状数组

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int N = 1e6+10;int n;
int h[N], tr[N];
LL sum[N];int lowbit(int x)
{return x & -x;
}void add(int a, int b)
{for(int i = a; i < N; i += lowbit(i)) tr[i] += b;
}LL query(int x)
{LL res = 0;for(int i = x; i; i -= lowbit(i)) res += tr[i];return res;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 0; i < n; ++i) cin >> h[i], h[i]++;for(int i = 0; i < n; ++i){sum[i] += query(N - 1) - query(h[i]);add(h[i], 1);}memset(tr, 0, sizeof tr);for(int i = n - 1; i >= 0; --i){sum[i] += query(h[i] - 1);add(h[i], 1);}LL res = 0;for(int i = 0; i < n; ++i) res += (1 + sum[i]) * sum[i] / 2;cout << res << endl;return 0;
}

五、超级快速排序

标签:归并排序

思路:其实就是求逆序对的数量,拿归并排序一做即可。

题目描述:

在这个问题中,您必须分析特定的排序算法----超快速排序。该算法通过交换两个相邻的序列元素来处理 n 个不同整数的序列,直到序列按升序排序。对于输入序列 9 1 0 5 4,超快速排序生成输出 0 1 4 5 9。您的任务是确定超快速排序需要执行多少交换操作才能对给定的输入序列进行排序。输入格式
输入包括一些测试用例。每个测试用例的第一行输入整数 n,代表该用例中输入序列的长度。接下来 n 行每行输入一个整数 ai,代表用例中输入序列的具体数据,第 i 行的数据代表序列中第 i 个数。当输入用例中包含的输入序列长度为 0 时,输入终止,该序列无需处理。输出格式
对于每个需要处理的输入序列,输出一个整数 op,代表对给定输入序列进行排序所需的最小交换操作数,每个整数占一行。数据范围
0≤n<500000,一个测试点中,所有 n 的和不超过 500000。0≤ai≤999999999
输入样例:
5
9
1
0
5
4
3
1
2
3
0
输出样例:
6
0

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int N = 5e5+10;int n;
int a[N], backup[N];LL merge_sort(int l, int r)
{if(l >= r) return 0;LL res = 0;int mid = l + r >> 1;res = merge_sort(l, mid) + merge_sort(mid+1, r);int i = l, j = mid + 1, k = 0;while(i <= mid && j <= r){if(a[i] <= a[j]) backup[k++] = a[i++];else{res += mid - i + 1;backup[k++] = a[j++];}}while(i <= mid) backup[k++] = a[i++];while(j <= r) backup[k++] = a[j++];for(int i = l, j = 0; i <= r; ++i, ++j) a[i] = backup[j];return res;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);while(cin >> n, n){for(int i = 0; i < n; ++i) cin >> a[i];LL res = merge_sort(0, n-1);cout << res << endl;}return 0;
}

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

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

相关文章

PG的JDBC对SQL中绑定变量个数的限制

瀚高数据库 目录 环境 症状 问题原因 解决方案 环境 系统平台&#xff1a;N/A 版本&#xff1a;N/A 症状 问题 有开发人员使用一条Insert values 语句&#xff0c;插入多行数据。例如&#xff1a;表A有88个字段&#xff0c;一条INSERT values …中包含500条数据。 报错…

六、矩阵问题

73、矩阵置零&#xff08;中等&#xff09; 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a…

应用案例 | Softing echocollect e网关助力汽车零部件制造商构建企业数据库,提升生产效率和质量

为了提高生产质量和效率&#xff0c;某知名汽车零部件制造商采用了Softing echocollect e多协议数据采集网关——从机器和设备中获取相关数据&#xff0c;并直接将数据存储在中央SQL数据库系统中用于分析处理&#xff0c;从而实现了持续监控和生产过程的改进。 一 背景 该企业…

【国家机关办公建筑 大型公共建筑的能耗监测、集中统一管理】安科瑞能耗监测系统整体解决方案

背景 为全面推进大型公建节能管理工作&#xff0c;需建立大型公建节能监管体系&#xff0c;逐步建立起全国联网的大型公建能耗监测平台&#xff0c;在大型公建安装分项计量装置&#xff0c;通过远程传输等手段及时采集分析能耗数据&#xff0c;实现对大型公建的实时动态监测、汇…

Qt应用软件【文件篇】Linux平台QFileSystemWatcher与QFile操作GPIO

文章目录 GPIO权限问题使用Root权限运行应用程序更改GPIO文件的权限使用udev规则自动设置权限监视GPIO与读写GPIO注意事项GPIO权限问题 在Linux系统中,通过sysfs接口操作GPIO时,经常会遇到权限问题,因为默认情况下,访问/sys/class/gpio目录及其文件需要root权限。这可能会…

Docker数据卷的挂载

目录 1 概念 2 常用命令 3 操作步骤(主要讲在创建容器时的挂载) 3.1 挂载在默认目录 3.2 挂载在自定义目录 4 附加内容(查看容器的挂载情况) 1 概念 数据卷&#xff08;volume&#xff09;是一个虚拟目录&#xff0c;是容器内目录与宿主机目录之间映射的桥梁。这样容器内…

go语言基础 -- json的序列化

json序列化 package main import("fmt""encoding/json" )type Monster struct{Name stringAge intSkill string }// 结构体序列化 func serialize_struct() {monster : Monster{Name : "niumo",Age : 500,Skill : "bajiaoshan",}// 这…

微服务day05-Gateway网关

Gateway网关 为了防止微服务能被任何身份的人访问&#xff0c;需要对访问微服务的人做身份认证和权限校验。网关的功能就是对访问用户进行身份认证和权限校验。网关具有3种功能&#xff1a; 身份验证和权限校验&#xff1a;网关作为微服务入口&#xff0c;需要校验用户是是否…

git 如何将多个提交点合并为一个提交点 commit

文章目录 核心命令详细使用模式总结示例 核心命令 git merge branch2 是将分支branch2的提交点合并到本地当前分支。 而在执行这条命令的时候&#xff0c;加一个选项--squash就表示在合并的时候将多个提交点合并为一个提交点。 git merge --squash branch2 先看squash单词的意…

[网络安全提高篇] 一二五.恶意软件分析之PE文件解析和利用Python获取样本时间戳及溯源

2024新的战场,继续奋斗。 “网络安全提高班”新的100篇文章即将开启,包括Web渗透、内网渗透、靶场搭建、CVE复现、攻击溯源、实战及CTF总结,它将更加聚焦,更加深入,也是作者的慢慢成长史。换专业确实挺难的,Web渗透也是块硬骨头,但我也试试,看看自己未来四年究竟能将它…

React Hooks 完全指南:无类组件革命

目录 ​编辑 前言 Hooks的前世 函数组件 类组件 状态和生命周期的管理 Hooks用途以及相应代码 状态管理 用于生命周期管理和副作用操作的 Hooks 用于上下文管理的 Hooks 其他用途的 Hooks 前言 React Hooks 是在 React 16.8 版本中引入的一个非常强大的新特性&…

建筑外窗遮阳系数测试的太阳光模拟器

太阳光模拟器是一种用于测试建筑外窗遮阳系数的高科技设备。它能够模拟太阳光照射房屋的情景&#xff0c;帮助建筑师和设计师更好地了解建筑外窗的遮阳性能&#xff0c;从而提高建筑的能源效率和舒适度。 这种模拟器的工作原理非常简单&#xff0c;它通过使用高亮度的光源和精…

scrapy 爬虫:多线程爬取去微博热搜排行榜数据信息,进入详情页面拿取第一条微博信息,保存到本地text文件、保存到excel

如果想要保存到excel中可以看我的这个爬虫 使用Scrapy 框架开启多进程爬取贝壳网数据保存到excel文件中&#xff0c;包括分页数据、详情页数据&#xff0c;新手保护期快来看&#xff01;&#xff01;仅供学习参考&#xff0c;别乱搞_爬取贝壳成交数据c端用户登录-CSDN博客 最终…

Bee Mobile组件库重磅升级

Bee Mobile组件库重磅升级&#xff01; 丰富强大的组件移动预览快速上手create-bee-mobile Bee Mobile组件库重磅升级&#xff01; Bee Mobile组件库最新 v1.0.0 版本&#xff0c;支持最新的 React v18。 主页&#xff1a;Bee Mobile 丰富强大的组件 一共拥有50多个组件&…

Linux 常用命令汇总(一):查询帮助 文件压缩及解压缩 搜索文件

一、线上查询及帮助命令 1.1 man 1.1.1 介绍 man 命令用于显示命令手册页面&#xff08;manual pages&#xff09;&#xff0c;提供了关于命令、函数、系统调用等的详细文档和使用说明 1.1.2 使用方法 man [选项] [命令或函数或系统调用]1.1.3 参数详解 -f&#xff1a;显…

Java面向对象总结 ( 知识点 | 代码详解 )

类和对象 什么是类&#xff1f; ● 概念&#xff1a;具有相同特征&#xff08;同一类&#xff09;事物的抽象描述&#xff0c;如人类&#xff0c;车类&#xff0c;学生类等。 类的结构&#xff1a; ● 变量: 事物属性的描述(名词) ● 方法: 事物的行为&#xff08;可以做…

基于Flask的宠物领养系统的设计与实现

基于Flask的宠物领养系统的设计与实现 涉及技术&#xff1a;python3.10flaskmysql8.0 系统分为普通用户和管理员两种角色&#xff0c;普通用户可以浏览搜索宠物&#xff0c;申请领养宠物&#xff1b;管理员可以分布宠物信息&#xff0c;管理系统等。 采用ORM模型创建数据&am…

QT----云服务器部署Mysql,Navicat连接1698 -Access denied for user ‘root‘@‘‘

阿里云有活动&#xff0c;白嫖了一年的新加坡轻量级服务器&#xff0c;有点卡&#xff0c;有时候要开梯子 白嫖300元优惠券 目录 1 安装启动Mysql服务2 更改连接权限2.1 Navicat连接报错1698 -Access denied for user root 3 qt连接云服务器数据库 1 安装启动Mysql服务 我使用…

f5——>字符串三角

暴力破解&#xff0c;双层循环&#xff0c;注意复制到新列表用append&#xff0c;这样更不容易出错 格式还是“”.join(str)

eNSP(Enterprise Network Simulation Platform)详细介绍

一、引言 随着网络技术的快速发展&#xff0c;网络设备的种类和功能日益增多&#xff0c;网络拓扑结构也变得越来越复杂。这对于学习网络技术、设计网络方案以及进行网络设备的测试都提出了更高的要求。为了满足这些需求&#xff0c;华为推出了eNSP&#xff08;Enterprise Net…