【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解)

这篇具有很好参考价值的文章主要介绍了【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

目录

1、题目介绍

2、解题思路

2.1、暴力破解法

2.2、归并排序思想

2.2.1、画图详细讲解

2.2.2、归并排序解决逆序对的代码实现

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

1、题目介绍

首先阅读题目可以得出要点,即当前数大于后数时则当作一个【逆序对】,而题目是要求在一个数组中计算一共存在多少个这样的逆序对并输出结果。 

 原题链接:LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

2、解题思路

2.1、暴力破解法

看到这里的第一反应就是这不是很简单吗?心想着这困难题也不过如此吧(笑)。

就是直接使用暴力破解法,只需要两个for循环嵌套,一个record[ i ]在原地,另一个record[ j ]将后面所有遍历一遍,只要比record[ i ]的小就将计算器count加1,然后i++再从头遍历,知道找完所有,最后返回计数器count即可,于是便奋笔疾书写了起来。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

int reversePairs(int* record, int recordSize) {
	if (recordSize == 0)
	{
		return 0;
	}
	int count = 0;
	int i = 0, j = 0;
	for (i = 0; i < recordSize - 1; i++)
	{
		for (j = i + 1; j < recordSize; j++)
		{
			if (record[i] > record[j])
			{
				count++;
			}
		}
	}
	return count;
}

 当写完然后测试了简答数据无误,然后自信满满地点击提交,结果却直接被打脸。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

看了报错结果才恍然大悟,看题目时漏看了数组长度。

题目设置的数组长度最长可达 50000,因此使用暴力破解法虽然非常简单,但是时间复杂度也非常大为O(n^2),这肯定会超出时间限制的。因此需要使用一种时间复杂度较小的遍历。到了这里才终于理解了这道题为什么是困难题!!!

2.2、归并排序思想

这里思考了一下,只要能找到 一种时间复杂度低,并且通过比较排序的算法,在比较排序的过程中顺便进行记录,这样的化就能够解决这个问题了。

于是归并排序便浮现在眼前,归并排序的时间复杂度很低只有O(nlogn),并且也是通过比较的方式进行排序,那么只需要在传统的归并排序算法中添加一些用于记录前者大于后者计算器即可。

 简单回顾一下归并排序的知识:

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用递归或者说是分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序,它包含这样三个步骤:

  • 分解:把长度为n的待排序序列分成两个长度为n/2的子序列。例如L代表头部,M代表中点,R代表尾部,将[ L,R ]分成[ L,M ]和[  M+1,R ]。
  • 解决:使用归并排序递归地排序两个子序列。
  • 合并:将两个排序好的子序列[ L,M ]和[  M+1,R ]合并成一个最终的排序序列。

在待排序序列长度为 1 的时候,递归开始「回升」,因为我们默认长度为 1 的序列是排好序的。简单来说就是:当分到单个子序列只剩下一个数字时,一个数字就是天然了有序,即此时左侧和右侧都排好序了,然后递归进行回升操作。

由于篇幅原因,如果想要更加详细地了解有关归并排序的知识,可以前往往期博客中阅读:

【算法与数据结构】归并排序的代码实现(详细图解)以及master公式的讲解_Hacynn的博客-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/133516177?spm=1001.2014.3001.5501

2.2.1、画图详细讲解

假设我们通过归并排序的「回升」操作已经得到了两个已排序的子序列并等待合并,这两个子序列假设为:左子序列[ 8,15,17,22,35 ]和右子序列[ 9,12,15,30,38 ]。然后用malloc开辟辅助数组help,并定义一个变量sum用于记录当前逆序对的个数。

一开始我们先用p1指向子序列的头部,p2指向子序列的头部,i指向help数组的头部。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

此时开始比较p1和p2指向的值,我们发现p1小于p2,不符合逆序对的前者大于后者,因此不做其他操作,直接将值放入help数组 i 位置中,并且分别进行p1++和i++,使指向下一个元素。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

重复p1和p2的比较操作,发现此时p1大于p2,此时记录逆序对的sum本应该自增1。

但是这里我们可以发现一个规律:因为左子序列是有序的,如果p1此时的数比p2大,那就证明p1后面的数字也依然比p2大,因此逆序对应该有M-p1+1即4个,分别是:(15,9)、(17,9)、(22,9)、(35,9)。

所以此时sum应该+4,并将p2所指的较小值存入help中。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

 i++、p2++;

此时p1仍然大于p2,再次使用M-p1+1计算出逆序对为4个,分别是(15,12)、(17,12)、(22,12)、(35,12)

此时 sum =  sum+4,并将12存入help中。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

 i++,p2++;

注意特殊:此时p1 == p2,该算法在等于时尤为关键,当相等时应该将左侧p1的15放入help中并p1++,如果放的是右侧p2的15存入,就会丢失一部分逆序对,这个原理读者可以自己画图理解。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

剩下的部分依然按照此规律进行操作,最终算出该轮遍历的逆序对数sum。 

2.2.2、归并排序解决逆序对的代码实现

int ExternalSort(int* arr, int L, int M, int R)
{
	int* help = (int*)malloc(sizeof(int) * (R - L + 1));
	int p1 = L;
	int p2 = M + 1;
	int sum = 0;
	int i = 0;
	while ((p1 <= M) && (p2 <= R))
	{
        //p1 大于 p2 则计算出逆袭对个数并加入sum中,p1小于p2时则给0(即不操作)
		sum += arr[p1] > arr[p2] ? (M - p1 + 1) : 0;
        //较小的数拷贝进help数组,相等时拷贝p1指针的数
		help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
	}
    //当有一个子序列遍历完了,则将另外一个子序列中剩余的数据全部放入help数组中
	while (p1 <= M) { help[i++] = arr[p1++]; }
	while (p2 <= R) { help[i++] = arr[p2++]; }
    //将辅助数组help中已经合并完成的数据传回给原数组arr的相应位置
	for (i = 0; i < (R - L + 1); i++)
	{
		arr[L + i] = help[i];
	}
	free(help);
	help = NULL;
	return sum;  //返回本轮操作的sum值

}

int MergeSort(int* arr, int L, int R)
{
	if (L == R)
	{
		return 0;
	}
	int mid = L + (R - L) / 2;
	return MergeSort(arr, L, mid) +   //对拆分的左子序列进行递归操作
		MergeSort(arr, mid + 1, R) +  //对拆分的右子序列进行递归操作
		ExternalSort(arr, L, mid, R);  //外部排序并计算出逆序对sum
}

int reversePairs(int* record, int recordSize) {
	int ret = 0;
	if (recordSize == 0)    //对空数组进行判断
	{
		return 0;
	}
	ret = MergeSort(record, 0, recordSize - 1);
	return ret;
}

到这里,关于本题的解题过程就结束了 。

【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解),LeetCode刷题,算法,排序算法,c语言,leetcode,数据结构

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!文章来源地址https://www.toymoban.com/news/detail-712799.html

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

到了这里,关于【LeetCode力扣】LCR170 使用归并排序的思想解决逆序对问题(详细图解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【排序算法】 归并排序详解!深入理解!思想+源码实现!

    🎥 屿小夏 : 个人主页 🔥个人专栏 : 算法—排序篇 🌄 莫道桑榆晚,为霞尚满天! ​ 什么是归并?通过归并排序就能让数据有序?分治法是怎么在归并排序上应用的?本文将对归并排序进行细致入微的讲解,庖丁解牛般让你彻底明白归并排序! 归并排序(MERGE-SORT)是建

    2024年02月06日
    浏览(46)
  • 多种方法解决leetcode经典题目-LCR 155. 将二叉搜索树转化为排序的双向链表, 同时弄透引用变更带来的bug

    这段代码实际上是一个常见的算法题目的解法,目标是将一个二叉搜索树转换为一个排序的双向链表。整个过程是通过中序遍历来实现的,遍历过程中修改节点的左右指针来构建双向链表。代码中使用了一个额外的节点 dummy 来帮助构建双向链表,并使用 pre 节点来保存前一个

    2024年02月06日
    浏览(46)
  • 力扣hot100 排序链表 归并排序 递归

    Problem: 148. 排序链表 👩‍🏫 参考 ⏰ 时间复杂度: O ( n ) O(n) O ( n ) 🌎 空间复杂度: O ( n ) O(n) O ( n )

    2024年01月25日
    浏览(42)
  • 【Leetcode刷题(数据结构)】:三路划分与三数随机取中的思想实现快速排序的再优化

    快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程

    2024年02月08日
    浏览(46)
  • #力扣:LCR 182. 动态口令@FDDLC

    LCR 182. 动态口令 一、Java 二、C++ 三、Python 四、JavaScript 五、Go

    2024年02月07日
    浏览(97)
  • 【LeetCode力扣】75 快速排序的子过程partition(荷兰国旗问题)

    目录 1、题目介绍 2、解题思路 2.1、冒泡排序暴力破解 2.2、快速排序的子过程partition 2.2.1、详细过程描述 2.2.2、代码描述 原题链接: 75. 颜色分类 - 力扣(LeetCode) 示例 1: 输入:nums = [2,0,2,1,1,0] 输出:[0,0,1,1,2,2] 示例 2: 输入:nums = [2,0,1] 输出:[0,1,2]   提示: n == nums.len

    2024年02月08日
    浏览(37)
  • 算法:分治思想处理归并递归问题

    利用归并思想进行分治也是很重要的一种思路,在解决逆序对的问题上有很大的需求空间 于是首先归并排序是首先的,归并排序要能写出来: 以上为归并排序基本算法原理,基于这个原理可以解决逆序对问题,逆序对问题通常问法是,给定某一个数据,在整个数组中找比这

    2024年02月10日
    浏览(42)
  • 力扣LCR 166. 珠宝的最高价值(java 动态规划)

    Problem: LCR 166. 珠宝的最高价值 改题目与本站64题实质上是一样的,该题目在64题的基础上将求取 最小路径和 改成了求取 最大路径和 。具体实现思路如下: 1.定义一个int类型的二维数组dp大小为给定矩阵frame的行数与列数。该数组用于记录每个当前阶段的 最大路径和 (也是本

    2024年02月01日
    浏览(46)
  • 湘大 XTU OJ 1097 排序 题解:c++ 函数库的使用 快速排序 归并排序 冒泡排序

    1097 排序 Description N个整数,将其排序输出。 输入 第一行是一个整数K(1=K=20),表示有多少个样例, 每个样例的第一行是一个整数N(1=N=1,000) 和一个字符X,X为A时表示升序排序,为D时为降序排列;第二行为N个整数,每个整数都可以使用int表示, 每个之间用一个空格隔开。

    2024年02月13日
    浏览(42)
  • ⭐北邮复试刷题LCR 037. 行星碰撞__栈 (力扣119经典题变种挑战)

    给定一个整数数组 asteroids,表示在同一行的小行星。 对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。 找出碰撞后剩下的所有小行星。碰撞规则:两个行星相互碰撞

    2024年02月22日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包