归并排序(归并排序求逆序对数)--16--归并排序--Leetcode面试题51.数组中的逆序对

面试题51. 数组中的逆序对

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

示例 1:

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

限制:

0 <= 数组长度 <= 50000

 

归并排序简介:

    归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

  将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并(如下图)。

  归并排序时间复杂度为NlogN,仅次于快速排序(点击链接可看我之前发过的快排博文),为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列

                  归并排序

归并排序举例:

    如设有数列{6,202,100,301,38,8,1}

    初始状态:6,202,100,301,38,8,1

    第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

    第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

    第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

    总的比较次数为:3+4+4=11;

    逆序对数为14对;

归并排序求逆序对数:具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数(也可以用 树状数组来求解)

代码解析:

 1 class Solution {
15     //归并排序:
16     int reversepairs = 0;//逆序对数
17     public int[] mergeSort(int[] nums, int left, int right){//归并排序函数
18         if (left == right)//如果左边界等于右边界,说明数组只有一个值,不用排序
19             return new int[] { nums[left] };
20         int mid =  (right + left) / 2;//将数组分为两半
21 
22         int[] leftArr = mergeSort(nums, left, mid); //左有序数组
23         int[] rightArr = mergeSort(nums, mid + 1, right); //右有序数组
24         int[] newNum = new int[leftArr.length + rightArr.length]; //新的有序数组
25 
26         int m = 0, i = 0, j = 0; 
27         //挨着挨着比较从左右两边的排好序的数组中从头开始比较,谁小就先放谁进新的有序空数组
28         while (i < leftArr.length && j < rightArr.length){//直到左右两个有序数组有一个的遍历下标超出该数组的序列尾部
29             if(leftArr[i] <= rightArr[j])//左序列的元素小,就把左序列的该元素放入新的空的有序数组中
30                 newNum[m++] = leftArr[i++];
31             else{//右序列的元素小,就把右序列的该元素放入新的空的有序数组中
32                 newNum[m++] = rightArr[j++];
33                 reversepairs += leftArr.length - i;//左边序列数组中还有leftArr.length-i个元素大于rightArr[j],所以这也是该区间的逆序对数35             }
36         }
37         while (i < leftArr.length)//如果左序列的元素还有剩余的元素没放进新的空数组中,就把左序列剩余元素放入新的空的有序数组中
38             newNum[m++] = leftArr[i++];
39         while (j < rightArr.length)//如果右序列的元素还有剩余的元素没放进新的空数组中,就把右序列剩余元素放入新的空的有序数组中
40             newNum[m++] = rightArr[j++];
41         return newNum;
42     }
43     public int reversePairs(int[] nums) {//入口函数
44         if(nums.length == 0)//如果给定的是个空数组,据题意返回0
45             return 0;
46         int[] newNums = mergeSort(nums, 0, nums.length - 1);//调用归并排序函数,返回一个有序的数组
47         return reversepairs;//返回逆序对数
48     }
49 }

    

posted @ 2020-04-24 21:00  我只是一个码农  阅读(393)  评论(0编辑  收藏  举报