归并排序 nO(lgn) 审核中
大家好,我是蓝胖子,我一直相信编程是一门实践性的技术,其中算法也不例外,初学者可能往往对它可望而不可及,觉得很难,学了又忘,忘其实是由于没有真正搞懂算法的应用场景,所以我准备出一个系列,囊括我们在日常开发中常用的算法,并结合实际的应用场景,真正的感受算法的魅力。
代码已经上传github
https://github.com/HobbyBear/codelearning/tree/master/mergesort
算法原理
每每实现算法的时候,我总是倾向于用文字将算法的逻辑描述出来,当你能清晰的描述算法逻辑的时候,实现起来就是水到渠成的事情。
所以,我们接下来首先看下归并排序的算法逻辑。归并排序的时间复杂度是nO(lg n),它要求每次 将数组一分为二,被分割的数组又一分为二直至不能被分割,最后由底向上进行两两合并。你可以看到,假设数组长度是n,整个过程一共有lg n层,每一层需要对n个元素进行合并,所以时间复杂度是nO(lg n)。如下图所示:

合并的过程是将合并的两个有序数组的元素变成一个有序数组的过程,我们把这个过程称为merge,于是我们将 归并排序的详细步骤总结为如下的步骤,
1,将数组一分为二,形成左右子数组。
2,对左子数组进行归并排序。
3,对右子数组进行归并排序。
4,对左右子数组进行merge。
详细的merge操作我们可以在O(n)时间复杂度内完成,详细步骤可以总结如下:
1,用i表示左子数组当前遍历的元素,j表示右边子数组当前遍历的元素。
2,创建一个新数组,用于保存排好序的元素,开始遍历左右子数组,如果左右子数组都没有遍历完,则比较各自当前遍历元素的大小,将小的元素复制到新数组,然后移动小元素所在数组当前遍历的指针指向下一个遍历元素。
3,如果其中一个数组遍历完成则只需要将,没有遍历完的那个数组剩下元素全部复制到新数组即可。
实现
了解了上述详细步骤后,我们可以很容易的用递归实现上述归并排序逻辑。
// 将数组[l...r]一分为二,分别对左右数组进行排序,然后对排序好的数组进行归并
func mergesort(arr []int, l, r int) {
if l >= r {
return
}
mid := (l + r) / 2
mergesort(arr, l, mid)
mergesort(arr, mid+1, r)
merge(arr, l, mid, r)
}
merge 部分代码如下,
写算法逻辑的时候一定要注意边界条件,比如我这里定义的是闭区间,那么下面的逻辑都是按闭区间去写的。
// [l...mid] [mid+1...r]
func merge(arr []int, l, mid, r int) {
arr1 := arr[l : mid+1]
arr2 := arr[mid+1 : r+1]
newArr := make([]int, r-l+1)
i := 0 // 当前遍历元素
j := 0
k := 0
for i < len(arr1) && j < len(arr2) {
if arr1[i] > arr2[j] {
newArr[k] = arr2[j]
j++
k++
continue
}
newArr[k] = arr1[i]
k++
i++
}
if i == len(arr1) {
copy(newArr[k:], arr2[j:])
}
if j == len(arr2) {
copy(newArr[k:], arr1[i:])
}
copy(arr[l:], newArr)
}
应用 求解逆序对的数量
关于归并排序的一个应用,我这里用leetcode一个题举例,这个题是leetcode 的剑指 Offer 51题,求解逆序对。
剑指 Offer 51. 数组中的逆序对
困难
1.1K
相关企业
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
这道题可以采用归并排序的思想,在merge时,得到逆序对的数量,如下,

merge时的两个数组是有序的,且归并排序的左右数组的相对顺序是不变的,当右边数组合并到左边数组时,如果左边的数组元素大,则说左边数组当前遍历的元素和其以后的元素都可以和右边的数组构成一个逆序对。
所以我们可以在merge的代码逻辑中添加一段累计逆序对的逻辑,如下:
func mergeCopy(arr []int, l, mid, r int, cnt *int) {
arr1 := arr[l : mid+1]
arr2 := arr[mid+1 : r+1]
newArr := make([]int, r-l+1)
i := 0 // 当前遍历元素
j := 0
k := 0
for i < len(arr1) && j < len(arr2) {
if arr1[i] > arr2[j] {
newArr[k] = arr2[j]
// 新增cnt 变量用于保存逆序对的数量
*cnt += len(arr1) - i
j++
k++
continue
}
newArr[k] = arr1[i]
k++
i++
}
if i == len(arr1) {
copy(newArr[k:], arr2[j:])
}
if j == len(arr2) {
copy(newArr[k:], arr1[i:])
}
copy(arr[l:], newArr)
}
归并排序 nO(lgn) 审核中的更多相关文章
- php大力力 [051节] 支付宝支付.申请支付资质,等待审核中
https://beecloud.cn/doc/payapply/?index=6 支付宝支付申请支付资质 一.注册支付宝用户 在支付宝官网注册成为用户 二.签约对应支付产品 应用集成支付宝支付,需要 ...
- 说说三四月的app审核中的几个坑
苹果的审核在3月异常严格,听说和换了部门领导有关(道听途说),恰逢三月公司新出了一个产品,我们的产品被苹果打回四五次,今天就在简书上把这些坑填下,也让遇到的朋友以后留意,也许是近期的最后一篇文章. 坑 ...
- [App Store Connect帮助]七、在 App Store 上发行(3.4)提交至“App 审核”:将构建版本从审核中移除
若要停止“App 审核”流程,您可以将该 App 版本从 App 审核中移除.要执行此项操作,App 状态必须为下列之一: 正在等待出口合规检查 正在等待审核 正在审核 等待开发者发布 等待 Appl ...
- 解决Google Play审核中的WebViewClient.onReceivedSslError问题
Google Play应用市场提交应用审核,出现因WebViewClient.onReceivedSslError问题导致拒绝通过. Google Paly给出的详情地址:support.google ...
- MergeSort归并排序和利用归并排序计算出数组中的逆序对
首先先上LeetCode今天的每日一题(面试题51. 数组中的逆序对): 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. ...
- MySQL 事务常见面试题总结 | JavaGuide 审核中
<Java 面试指北>来啦!这是一份教你如何更高效地准备面试的小册,涵盖常见八股文(系统设计.常见框架.分布式.高并发 ......).优质面经等内容. 本文原发于 MySQL知识点&am ...
- 九度OJ 1348:数组中的逆序对 (排序、归并排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2777 解决:656 题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组 ...
- 排序算法的C语言实现(上 比较类排序:插入排序、快速排序与归并排序)
总述:排序是指将元素集合按规定的顺序排列.通常有两种排序方法:升序排列和降序排列.例如,如整数集{6,8,9,5}进行升序排列,结果为{5,6,8,9},对其进行降序排列结果为{9,8,6,5}.虽然 ...
- 告别被拒,如何提升iOS审核通过率(上篇)
iOS审核一直是每款移动产品上架苹果商店时面对的一座大山,每次提审都像是一次漫长而又悲壮的旅行,经常被苹果拒之门外,无比煎熬.那么问题来了,我们有没有什么办法准确把握苹果审核准则,从而提升审核的通过率 ...
- 047医疗项目-模块四:采购单模块—采购单审核提交(Dao,Service,Action三层)
我们之前把采购单都审核了,这篇文章说的就是审核之后提交. 其实就是改变(update)采购单的审核状态. 需求: 用户要先查看采购单的内容. 查看采购单页面:页面布局同采购单修改页面. 选择审核结果. ...
随机推荐
- 【WALT】scale_exec_time() 代码详解
@ 目录 [WALT]scale_exec_time() 代码详解 代码展示 代码逻辑: 为什么归一化? ⑴ 将 CPU cycles 转换为 CPU 当前频率 ⑵ 归一化 delta [WALT]s ...
- PHP递归和循环的速度测试
本文于 2017-12-05 重新整理. 写了一个可以对 $_GET, $_POST 等输入进行过滤的函数,递归实现如下: function array_map_recursive($filters, ...
- Mysql生成测试数据函数
1.查看设置是否允许创建函数系统参数 show variables like 'log_bin_trust_function_creators'; 2.临时设置允许创建函数系统参数 set globa ...
- 简单运维oceanbase
简单运维oceanbase 数据库集群参数修改 直连 proxy 连接 手动修改参数 show parameters like '%xx%' ; alter system set xxx='xx'; ...
- 学好Linux的必经之路
学好Linux的必经之路 学习动机的培养对于一个人学习习惯的形成有着重要的作用.当我们在学习某一个事物时,建立属于我们自己的学习方法,以此培养我们学习Linux系统的学习动机. 当前,Linux系统属 ...
- 写一段python下载商品图片的代码
以下是一个简单的Python代码示例,用于下载商品图片: import requests import os def download_image(url, save_path): response ...
- async、await其实是generator和promise的语法糖
async 关键字用于声明异步函数,await 用于在async函数中将异步代码变为同步,阻塞代码的执行 对于promise和generator不熟悉的朋友可以移步看看这些文章 Promise的理解与 ...
- Flutter系列文章-实战项目
在本篇文章中,我们将通过一个实际的 Flutter 应用来综合运用最近学到的知识,包括保存到数据库.进行 HTTP 请求等.我们将开发一个简单的天气应用,可以根据用户输入的城市名获取该城市的天气信息, ...
- 形象谈JVM-第一章-认识JVM
对jvm的历史不做过多介绍,感兴趣的同学可以去自行搜索. 我们直接以HotSpot VM(Virtual Machine)举例. why 为什么要有虚拟机? 举一个形象的例子:手机现在几乎是人手一台 ...
- 面霸的自我修养:synchronized专题
王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群:共同富裕的Java人 今天是<面霸的自我修养>的第3弹,内容是Java并发编程中至关重要的关键字synchroni ...