算法刷题day23:归并排序

目录

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

引言

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


概念

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


一、火柴排队

标签:归并排序

思路:只要把 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/724920.shtml

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

相关文章

【详识C语言】动态内存管理

本章重点 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 几个经典的笔试题 柔性数组 为什么存在动态内存分配 我们已经掌握的内存开辟方式有&#xff1a; int val 20;//在栈空间上开辟四个字节char arr[10] {0};//在栈空间上开…

Three.js--》探寻Cannon.js构建震撼的3D物理交互体验(二)

我们用three.js可以绘制出各种酷炫的画面&#xff0c;但是当我们想要一个更加真实的物理效果的话&#xff0c;这个时候我们就需要一个物理的库&#xff0c;接下来我们就讲解一下今天要学习的canon&#xff0c;它可以给我们提供一个更加真实的物理效果&#xff0c;像物体的张力、…

程序员超强大脑——提高命名的质量(二)

哪些类型的标识符更容易理解 使用完整的单词似乎是一个合理的选择。虽然单词构成的标识符便于理解&#xff0c;但较长的标识符也可能产生负面影响。设计高质量的标识符是需要仔细衡量单词的清晰性与缩写的简洁性&#xff1a;注意单词的清晰性便于代码阅读者理解程序和排查错误…

粒子群算法优化ELMAN神经网络的分类预测,pso-elman

目录 背影 ELMAN神经网络的原理 ELMAN神经网络的定义 受限玻尔兹曼机(RBM) 灰狼算法原理 灰狼算法优化elman神经网络回归分析 基本结构 主要参数 数据 MATALB代码 结果图 展望 完整代码下载:粒子群算法优化ELMAN神经网络的分类预测资源-CSDN文库 https://download.csdn.net…

2024护网面试题精选(一)

0x00.基础漏洞篇 00-TOP10漏洞 1.SQL注入 2.失效的身份认证和会话管理 3.跨站脚本攻击XSS 4.直接引用不安全的对象 5.安全配置错误 6.敏感信息泄露 7.缺少功能级的访问控制 8.跨站请求伪造CSRF 9.实验含有已知漏洞的组件 10.未验证的重定向和转发 01-SQL注入漏洞 …

java多线程 简简单单的学它

java多线程 什么是线程 通俗的讲&#xff0c;就是一个软件里相互独立&#xff0c;同时运行的功能。比如我们打开B站&#xff0c;看视频时&#xff0c;我们会看到画面&#xff0c;听到声音&#xff0c;闪过的弹幕&#xff0c;这些都可以看作是一个线程。 在理解线程前&#x…

【Java_JSON】如何从JSON数据中提取value值

如何从JSON数据中提取value值&#xff1f; 首先将JSON数据转成字符串 创建JSONObject 对象 通过kv键值对的特性 使用key值来获取value 值 并输出 结果&#xff1a;

c++中锁定数据出现读写错误的例子

2010-4 程序出现了问题&#xff0c;引出了数据逻辑问题。 下面两个函数GetNextDataIndexW();和SetNextDataIndexW分别锁定&#xff0c; 导致了可能两个线程通过了GetNextDataIndexW();但是在SetNextDataIndexW出现数据写入错误。 这是一个典型的数据同步错误&#xff0c;也是…

mysql 中的一些重要函数

show create table user_profile 查看表结构 1.datediff(end_date,start_date)函数&#xff0c;now(), curdate() curtime() date_add(日期,interval num 时间) date_format(日期,格式) 4.select IFNULL(null,0); oracle 中nvl 函数 5.select IF(2 > 1, 2,0)&#xff…

c++: 缺省参数/默认参数的详解及其应用

c缺省参数/默认参数的详解及其应用 缺省参数是什么 #include<iostream> using namespace std;void func(int a 666) {cout << "a " << a << endl; } int main() {func(); //没有传参func(10); //传参return 0; }缺省参数就是在我们不进…

计算机体系结构:VLIW

原文来自知乎 计算机体系结构&#xff1a;VLIW 本文主要介绍计算机体系结构中的VLIW&#xff0c;以供读者能够理解该技术的定义、原理、应用。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;计算机杂记 &#x1f…

腾讯云服务器99元一年购买入口链接

腾讯云服务器99元一年购买入口链接如下&#xff0c;现在已经降价到61元一年&#xff0c;官方活动链接如下&#xff1a; 腾讯云99元服务器一年购买页面腾讯云活动汇聚了腾讯云最新的促销打折、优惠折扣等信息&#xff0c;你在这里可以找到云服务器、域名、数据库、小程序等等多种…

【uniapp】小程序自定义一个通用的返回按钮组件

左边箭头&#xff0c;右边文字可以自定义&#xff0c;但是不要太长&#xff0c;太长可以自己改 .back的width值&#xff0c;改宽一点。 用这个组件的时候首先要在pages.json里把导航栏变成自定义的&#xff1a; ,{"path" : "pages/test/test","style&…

C#常识篇(三)

内置类型字节大小 以下是 C# 中常见内置数据类型的字节大小&#xff1a; bool&#xff08;布尔&#xff09;类型&#xff1a;通常为 4 或者 8 字节。在不同平台上可能会有所不同。 byte&#xff08;无符号字节&#xff09;类型&#xff1a;始终为 1 字节。 sbyte&#xff08;有…

Goose:Golang中的数据库迁移工具

Goose&#xff1a;Golang中的数据库迁移工具 在Golang开发中&#xff0c;数据库迁移是一个常见的任务&#xff0c;用于管理数据库模式的演化和版本控制。Goose是一个轻量级的、易于使用的数据库迁移工具&#xff0c;专为Golang开发者设计。本文将介绍Goose的基本概念、用法和优…

智能驾驶规划控制理论学习01-自动驾驶系统介绍、规划控制模块介绍

目录 一、自动驾驶系统概述 二、规划控制模块介绍 1、规划控制架构 2、规划控制目标 3、Cartesian和Frenet坐标系 4、Frenet坐标系概览 5、解耦式规划和联合式规划 一、自动驾驶系统概述 目前被国内外广为接受的自动驾驶级别划分标准是 SAE&#xff…

Nano 33 BLE Sense Rev2学习第二节——手机蓝牙接收数据

Nano 33 BLE Sense Rev2需要下载的程序 #include <ArduinoBLE.h> #include "Arduino_BMI270_BMM150.h"float x, y, z; int degreesX 0; int degreesY 0;BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service// cre…

2024年两会-区块链方向-新质生产力-先进制造业集群

区块链寒冬还未散去&#xff0c;但区块链引发的信任革命&#xff0c;对生产关系的变革&#xff0c;对数字金融产生的广泛影响&#xff0c;对货币金融体系的完全重构&#xff0c;对数据融合和隐私安全带来的巨大冲击才刚刚开始&#xff0c;没有不好的技术&#xff0c;只有不好的…

XSS漏洞--概念、类型、实战--分析与详解[结合靶场pikachu]

目录 一、XSS概念简述 1、XSS简介&#xff1a; 2、XSS基本原理&#xff1a; 3、XSS攻击流程&#xff1a; 4、XSS漏洞危害&#xff1a; 二、XSS类型&#xff1a; 1、反射型XSS&#xff1a; 2、存储型XSS&#xff1a; 3、DOM型XSS&#xff1a; 三、靶场漏洞复现(pikach…

LVS四层负载均衡集群

简介 LVS&#xff08;Linux Virtual Server&#xff09;即Linux虚拟服务器&#xff0c;是由章文嵩博士主导的开源负载均衡项目&#xff0c;目前LVS已经被集成到Linux内核模块中。该项目在Linux内核中实现了基于IP的数据请求负载均衡调度方案&#xff0c;终端互联网用户从外部访…