小和问题

image.png
之所以能够使用归并排序进行解决,是因为归并排序在**merge**的时候,会进行两部分的比较,例如
image.png
每次merge都可以计算出在这次merge中形成的小和,最后相加即为答案

  1. public class xiaohe {
  2. public static void main(String[] args) {
  3. int[] array = new int[]{1,2,3};
  4. System.out.println(mergeSort(array, 0, array.length - 1));
  5. }
  6. //给数组中left到right范围的子序列做归并排序
  7. public static int mergeSort(int[] array,int left,int right) {
  8. if (left == right) {
  9. //说明这个子数组只有一个值了,一定是有序的,直接返回即可
  10. return 0;
  11. }
  12. //递归,再分子数组
  13. //先得到中间位置(mid = left + (right-left)/2)
  14. int mid = left + ((right-left) >> 1);
  15. return mergeSort(array,left,mid) +
  16. mergeSort(array,mid+1,right) +
  17. //左右子序列排好序了,现在把左右子序列做一个归并
  18. merge(array,left,mid+1,right);
  19. }
  20. //index1是左子序列的起始值
  21. //index2是有右子序列的起始值
  22. //right是右子序列的终点
  23. public static int merge(int[] array,int index1,int index2,int right) {
  24. //index1是左子序列的位置
  25. //index2是右子序列的位置
  26. int sum = 0 ;
  27. int left = index1;
  28. int[] tmp = new int[right-index1+1];
  29. int record = index2;
  30. int index = 0 ;
  31. while (index1 < record && index2<=right) {
  32. //如果左边比右边小,那左边这个数就要比右边这个数以及右边这个数还大的数小
  33. sum += array[index] < array[index2] ? (right-index2+1) * array[index1] : 0;
  34. tmp[index++] = array[index1]>=array[index2]? array[index2++]:array[index1++];
  35. }
  36. while (index1 < record) {
  37. tmp[index++] = array[index1++];
  38. }
  39. while (index2 <= right) {
  40. tmp[index++] = array[index2++];
  41. }
  42. for (int i=0;i<tmp.length;i++) {
  43. array[left+i] = tmp[i];
  44. }
  45. return sum;
  46. }
  47. }

逆序对问题

image.png
与小和问题类似,这个是求merge过程中,左侧子序列中的数比右侧子序列中的数更大的情况

  1. public class nixudui {
  2. public static void main(String[] args) {
  3. int[] array = new int[]{3,2,1};
  4. mergeSort(array, 0, array.length - 1);
  5. }
  6. //给数组中left到right范围的子序列做归并排序
  7. public static void mergeSort(int[] array,int left,int right) {
  8. if (left == right) {
  9. //说明这个子数组只有一个值了,一定是有序的,直接返回即可
  10. return ;
  11. }
  12. //递归,再分子数组
  13. //先得到中间位置(mid = left + (right-left)/2)
  14. int mid = left + ((right-left) >> 1);
  15. mergeSort(array,left,mid);
  16. mergeSort(array,mid+1,right);
  17. //左右子序列排好序了,现在把左右子序列做一个归并
  18. merge(array,left,mid+1,right);
  19. }
  20. //index1是左子序列的起始值
  21. //index2是有右子序列的起始值
  22. //right是右子序列的终点
  23. public static void merge(int[] array,int index1,int index2,int right) {
  24. //index1是左子序列的位置
  25. //index2是右子序列的位置
  26. int left = index1;
  27. int[] tmp = new int[right-index1+1];
  28. int record = index2;
  29. int index = 0 ;
  30. while (index1 < record && index2<=right) {
  31. //如果左边比右边大,那左边这个数和左子序列中大于左边的这个数 会与 右边的数形成逆序对
  32. if (array[index1] > array[index2]) {
  33. for (int i=index1;i<record;i++) {
  34. System.out.println("(" + array[i] + "," + array[index2] + ")");
  35. }
  36. }
  37. tmp[index++] = array[index1]>=array[index2]? array[index2++]:array[index1++];
  38. }
  39. while (index1 < record) {
  40. tmp[index++] = array[index1++];
  41. }
  42. while (index2 <= right) {
  43. tmp[index++] = array[index2++];
  44. }
  45. for (int i=0;i<tmp.length;i++) {
  46. array[left+i] = tmp[i];
  47. }
  48. }
  49. }