归并排序之求小和
小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组
的小和。
例子:
[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 }