如何利用归并排序的merge

这篇博客介绍了如何通过归并排序算法来计算一个整数数组中的逆序对数量。逆序对是指在数组中,若前面的元素大于后面的元素,则这两个元素构成一个逆序对。在归并排序过程中,先对左右子区间分别进行逆序对计数,再合并时统计额外的逆序对。博主详细解释了合并两个有序数组时逆序对的计算方法,并给出了相应的Java代码实现。
摘要由CSDN通过智能技术生成

数组中的逆序对

剑指offer51:https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/

题干:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5


思路:

  1. 首先要明确升序数组就没有所谓的逆序对,降序数组就是任意抽取两个元素都构成逆序对,换句话说,数完逆序对,我把可以把数过的区间进行排序,后续在统计别的逆序对对数的时候就可以避免重复计算

  2. 逆序对有两种数法,一种是数这个数后面有多少个元素比自己小,那针对这个位置的逆序对的对数就是多少个,反过来,也可以数一个元素前面有多少个元素比自己大,那就针对该位置有多少个逆序对,之所以不同时数前面和后面的逆序对,是因为我们想在两个升序区间范围内去数,所以联想到归并排序.

  3. 归并排序的时候就是先拆分成两个区间,我们可以先对左区间进行逆序对的确定,然后将其升序排序,然后再把右半边区间进行逆序对的确定,然后再把右半边区间进行升序排序,之所以要升序排序,就是为了防止后续合并的时候发生逆序对的重复计算,当然除了两个子区间的逆序对数目的确定,两个子区间在合并的时候再统计整个的逆序对的个数,可以发现左右子区间虽然升序排序了,但是并不影响左右区间内的元素构成逆序对的个数情况.

  4. 如何在合并两个有序数组的时候统计逆序对的个数呢?看图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwtY9oyj-1654138436278)(C:\Users\lebronHArden\AppData\Roaming\Typora\typora-user-images\image-20220602104130533.png)]

    之所以在研究两个有序数组的逆序对如何去统计,是因为我们根据递归函数的含义已经明确了左右子区间已经完成了逆序对的统计,统计完成各自已经有序,所以我们只需要处理好两个升序数组如何统计逆序对个数即可.(并且单个元素肯定有序…)

    言归正传:统计上述两个有序数组的逆序对个数时,此处采用的是后半边区间内j遍历到的元素在前半边区间有几个元素比自己大,那j下标的元素就可以为逆序对总数贡献几.

    比如原始数组依次被覆盖:1,然后i++,2和4比较要放2了,此时的4,5,8都是比自己大的,所以2的位置为计数器贡献3,可以观察发现这个3正是mid-i+1得来的.

  5. 所以经过上述论述可以写出如下代码:

class Solution {
    public int reversePairs(int[] nums) {
        if(nums==null||nums.length<2) return 0;
        //临时数组,或者说是辅助数组
        int[] temp = new int[nums.length];
        return mergerSort(nums,0,nums.length-1,temp);
    }

    private int mergerSort(int[] nums, int left, int right,int[] temp) {
        if(left==right) return 0;
        int mid = left+(right-left)/2;
        int leftPairs = mergerSort(nums,left,mid,temp);
        int rightPairs = mergerSort(nums,mid+1,right,temp);
        int crossPairs = merge(nums,left,mid,right,temp);
        return leftPairs+rightPairs+crossPairs;
    }

    private int merge(int[] nums, int left, int mid, int right, int[] temp) {
        for(int i = left;i<=right;i++){
            temp[i]=nums[i];
        }
        int i = left;
        int j = mid+1;
        int count=0;
        for(int k = left;k<=right;k++){
            if(i==mid+1){
                nums[k]=temp[j];
                j++;
            }else if(j==right+1){
                nums[k]=temp[i];
                i++;
            } else if(temp[i]<=temp[j]){
                nums[k]=temp[i];
                i++;
            }else{
                nums[k]=temp[j];
                j++;
                count+=mid-i+1;
            }
        }
        return count;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
合并排序(Merge Sort)是一种基于分治思想的排序算法,它的核心思想是将待排序的数组逐步划分为较小的子数组,然后对这些子数组进行排序,最后将它们合并成一个有序的数组。C语言实现合并排序算法的过程中,通常需要用到递归算法和归并操作。下面是一个简单的C语言合并排序算法的实现: ``` void merge(int arr[], int left, int mid, int right) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; int L[n1], R[n2]; for (i = 0; i < n1; i++) L[i] = arr[left + i]; for (j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; i = 0; j = 0; k = left; while (i < n1 && j < n2) { if (L合并排序(Merge Sort)是一种基于分治思想的排序算法,它的核心思想是将待排序的数组逐步划分为较小的子数组,然后对这些子数组进行排序,最后将它们合并成一个有序的数组。C语言实现合并排序算法的过程中,通常需要用到递归算法和归并操作。下面是一个简单的C语言合并排序算法的实现: ``` void merge(int arr[], int left, int mid, int right) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; int L[n1], R[n2]; for (i = 0; i < n1; i++) L[i] = arr[left + i]; for (j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; i = 0; j = 0; k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } void mergeSort(int arr[], int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); merge(arr, left, mid, right); } } int main() { int arr[] = { 12, 11, 13, 5, 6, 7 }; int n = sizeof(arr) / sizeof(arr[0]); mergeSort(arr, 0, n - 1); printf("Sorted array: \n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); return 0; } ``` 在这个实现中,merge() 函数实现了将两个有序数组合并为一个有序数组的操作。mergeSort() 函数归并排序的核心递归函数,它将数组逐步划分为较小的子数组,并调用 merge() 函数进行合并。最后,main() 函数用于测试归并排序算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值