过程

  • 分解:将n 个元素分成个含n/2 个元素的子序列;
  • 解决:对两个子序列递归地排序
  • 合并:合并两个已排序的子序列以得到排序结果

和快排不同的是

  • 归并的分解较为随意
  • 重点是合并
  • 需要额外开辟数组空间

image

image

  1. public static void mergeSort(int[] arr){
  2. if(arr == null||arr.length<2) return; //数组元素至少为2
  3. mergeSort(arr,0,arr.length-1);
  4. }
  5. public static void mergeSort(int[] arr,int L, int R){
  6. if(L == R) return; //递归边界
  7. int mid = L+((R - L) >> 1); //注意这里的移位运算的括号不能少
  8. mergeSort(arr,L,mid); //左侧数组归并排序
  9. mergeSort(arr, mid+1, R); //右侧数组归并排序
  10. merge(arr, L, mid, R);
  11. }
  12. public static void merge(int[] arr, int L, int m, int R){
  13. int[] help = new int[R-L+1]; //辅助数组
  14. int i = 0; //辅助数组下标
  15. int p1 = L; //第一个待合并数组起点
  16. int p2 = m + 1; //第二个待合并数组起点
  17. while(p1 <= m && p2 <= R){ //排好的部分拷贝到辅助数组
  18. help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
  19. }
  20. while(p1 <= m){ //继续处理剩下的数组
  21. help[i++] = arr[p1++];
  22. }
  23. while(p2 <= R){ //继续处理剩下的数组
  24. help[i++] = arr[p2++];
  25. }
  26. for (int j = 0; j < help.length; j++) { //拷贝回原数组
  27. arr[L + j]=help[j];
  28. }
  29. }

套用master公式T(N) = a*T(N/b) + O(N^d)
a=2,b=2,d=1
log(b,a) = d -> 时间复杂度为O(N^d * logN) =O(NlogN)
额外空间复杂度 O(N)

所以:

  • 时间复杂度:O(NlogN)
  • 空间复杂度:O(N)
  • 稳定性:稳定
  • 非原址排序

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

  1. 示例 1:
  2. 输入: [7,5,6,4]
  3. 输出: 5
  4.  
  5. 限制:
  6. 0 <= 数组长度 <= 50000

稍微修改一下归并排序代码即可

  1. class Solution {
  2. private int ans = 0; //声明实例变量
  3. public int reversePairs(int[] nums) {
  4. mergeSort(nums, 0, nums.length - 1);
  5. return ans;
  6. }
  7. public void mergeSort(int[] arr, int low, int high) {
  8. if (arr.length < 2 || low >= high) return;
  9. int mid = low + ((high - low) >> 1);
  10. mergeSort(arr, low, mid);
  11. mergeSort(arr, mid + 1, high);
  12. merge(arr, low, mid, high);
  13. }
  14. public void merge(int[] arr, int low, int mid, int high) {
  15. int[] helper = new int[high - low + 1];
  16. int i = low;
  17. int j = mid + 1;
  18. int k = 0;
  19. while (i <= mid && j <= high) {
  20. if (arr[i] <= arr[j]) {
  21. helper[k++] = arr[i++];
  22. } else {
  23. ans += mid - i + 1; //注意:如果arr[i]>arr[j]则i~mid这个区间的所有数都大于arr[j],因为[low……mid]和[mid+1……high]是已经排好序的。
  24. helper[k++] = arr[j++];
  25. }
  26. }
  27. while (i <= mid) {
  28. helper[k++] = arr[i++];
  29. }
  30. while (j <= high) {
  31. helper[k++] = arr[j++];
  32. }
  33. for (int m = 0; m < helper.length; m++) {
  34. arr[low + m] = helper[m];
  35. }
  36. }
  37. }

版权声明:本文为gonghr原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/gonghr/p/15104130.html