归并排序之求小和

Posted zqr99

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序之求小和相关的知识,希望对你有一定的参考价值。

小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组
的小和。
例子:
[1,3,4,2,5]
1左边比1小的数, 没有;
3左边比3小的数, 1;
4左边比4小的数, 1、 3;
2左边比2小的数, 1;
5左边比5小的数, 1、 3、 4、 2;
所以小和为1+1+3+1+1+3+4+2=16


如果直接用两层for循环扫一遍,时间复杂度O(n*n),这个题目可以利用归并排序把时间复杂度降到O(nlogn)
 

技术图片
 1 package com.sort.demo;
 2 
 3 public class Mergesort extends Sort {
 4 
 5     @Override
 6     public void sort(int[] arr) {
 7         if (arr == null || arr.length < 2)
 8             return;
 9         processSort(arr, 0, arr.length - 1);
10     }
11 
12     public void processSort(int[] arr, int L, int R) {
13         if (L == R)
14             return;
15         int mid = (L + R) / 2;
16         //左边排序
17         processSort(arr, L, mid);
18         //右边排序
19         processSort(arr, mid + 1, R);
20         merge(arr, L, mid, R);
21     }
22 
23     public void merge(int[] arr, int L, int mid, int R) {
24 
25         if (arr == null || arr.length < 2)
26             return;
27         int[] help = new int[R - L + 1];
28         int i = 0;
29         int p1 = L;
30         int p2 = mid + 1;
31         //左右两边的有序数组都不越界
32         while (p1 <= mid && p2 <= R) {
33             help[i++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++];
34         }
35         //右边越界,左边依次copy到结果数组
36         while (p1 <= mid) {
37             help[i++] = arr[p1++];
38         }
39 //        左边越界,右边依次copy到结果数组
40         while (p2 <= R) {
41             help[i++] = arr[p2++];
42         }
43         //再copy回原数组
44         for (i = 0; i < help.length; i++) {
45 //            很容易出错的地址,这个地方应该是L+i,而不是i,因为从arr的L到R合并
46             arr[L + i] = help[i];
47         }
48     }
49 
50     public static void main(String[] args) {
51         int[] arr = new int[]{1, 3, 4, 2, 5};
52         SmallSum smallSum = new SmallSum();
53         smallSum.sort(arr);
54     }
55 
56     //使用归并排序做小和
57     static class SmallSum extends Sort {
58 
59         @Override
60         public void sort(int[] arr) {
61             if (arr == null || arr.length < 2)
62                 return;
63             int sum = 0;
64             sum += mergeSort(arr, 0, arr.length - 1);
65             System.out.println(sum);
66         }
67 
68 
69         private int mergeSort(int[] arr, int L, int R) {
70             if (L == R)
71                 return 0;
72             int mid = L + ((R - L) >> 1);
73             return mergeSort(arr, L, mid) + mergeSort(arr, mid + 1, R) + merge(arr, L, mid, R);
74         }
75 
76         private int merge(int[] arr, int L, int mid, int R) {
77             int res = 0;
78             int p1 = L;
79             int p2 = mid + 1;
80             int i = 0;
81             int[] help = new int[R - L + 1];
82             while (p1 <= mid && p2 <= R) {
83                 res += arr[p1] < arr[p2] ? (R - p2 + 1) * arr[p1] : 0;
84                 help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
85             }
86             while (p1 <= mid) {
87                 help[i++] = arr[p1++];
88             }
89             while (p2 <= R) {
90                 help[i++] = arr[p2++];
91             }
92             for (i = 0; i < help.length; i++) {
93                 arr[L + i] = help[i];
94             }
95             return res;
96         }
97     }
98 }
求小和

 

以上是关于归并排序之求小和的主要内容,如果未能解决你的问题,请参考以下文章

归并排序应用-------小和问题

归并排序:小和问题

归并排序解决小和问题和逆序对问题

小和问题和逆序对问题

ACM常见问题之求逆序对

求小和问题