归并排序应用——剑指 Offer 51. 数组中的逆序对
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序应用——剑指 Offer 51. 数组中的逆序对相关的知识,希望对你有一定的参考价值。
(文章目录)
题目
1.错误示范
int reversePairs(int* nums, int numsSize)
int i = 0;
int j = 0;
int sum = 0;
for (i = 0; i < numsSize; i++)
for (j = i + 1; j < numsSize; j++)
if (nums[i] > nums[j])
sum++;
return sum;
2. 分析
逆序对的判断
统计出某个数后面有多少个数比它小
举例(完整过程解析)
第一次循环
第二次循环
第三次循环
第四次循环
第五次循环
循环结束的两种存在情况
<font color=red> 由于right数组已经遍历完,所以循环停止,再次判断两个数组是否存在数</font>
3. 正确代码
int mergesort1(int* nums, int left, int right, int* tmp)//归并排序
if (left >= right)
return 0;
int mid = (left + right) / 2;
int leftret = mergesort1(nums, left, mid, tmp);//计算左边区间 [left, mid] 中逆序对的数量 = leftRet,并排序;
int rightret = mergesort1(nums, mid + 1, right, tmp);//. 计算右边区间 [mid + 1, right] 中逆序对的数量 = rightRet,并排序
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int i = left;
int voeret = 0;//合并左右两个有序区间,并且计算逆序对的数量
while (begin1 <= end1 && begin2 <= end2)
if (nums[begin1] <= nums[begin2])
//当 nums[begin1] <= nums[begin2] 时,说明此时右边数组已经遍历过的元素都是比
// nums[begin1] 小的,因此累加到 voeret 中去
voeret += begin2 - (mid + 1);//因为计算的begin2刚开始的边界就为 mid+1
tmp[i++] = nums[begin1++];
else
//当 nums[begin1] > nums[begin2] 时,无需统计,直接归并
tmp[i++] = nums[begin2++];
//处理归并排序中剩余的元素;
//当左边有剩余的时候,还需要统计逆序对的数量;
//当右边还有剩余的时候,无需统计,直接归并。
while (begin1 <= end1)
voeret += begin2 - (mid + 1);
tmp[i++] = nums[begin1++];
while (begin2 <= end2)
tmp[i++] = nums[begin2++];
memcpy(nums + left, tmp + left, sizeof(int) * (right - left + 1));
return leftret + rightret + voeret;//返回 左区间逆序对数量 + 右区间逆序对数量 + 当前合并过程中产生的逆序对数量
int mergesort(int* nums, int numsSize)
int* tmp = (int*)malloc(sizeof(int) * numsSize);//因为我们不想一直malloc创建数组所以在外面开辟
int ret = mergesort1(nums, 0, numsSize - 1, tmp);
free(tmp);
tmp = NULL;
return ret;
int reversePairs(int* nums, int numsSize)
return mergesort(nums, numsSize);
4.递归展开图
以上是关于归并排序应用——剑指 Offer 51. 数组中的逆序对的主要内容,如果未能解决你的问题,请参考以下文章
剑指 Offer 51. 数组中的逆序对(归并排序,Java)