当前位置:   article > 正文

小和问题、逆序对问题_为什么小和问题可以转化成右边比它大

为什么小和问题可以转化成右边比它大

小和问题和逆序对问题是可以用归并排序来实现的。

小和问题:

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。

例子:

[1,3,4,2,5]

1左边比1小的数,没有;

3左边比4小的数,1;

4左边比4小的数,1、3;

2左边比2小的数,1;

5左边比5小的数,1、3、4、2;

所以小和为1+1+3+1+1+3+4+2 = 16

主要思想:

在归并的过程中比较,找出右边元素有多少比左边的元素大。如上面的数组,1右边有4个比1大的,那么1会出现4次。

实现代码(Java):

  1. package NewCoder;
  2. import java.util.Scanner;
  3. /**
  4. * 小和问题
  5. * 在一个数组中,每一个数左边比当前数小的累加起来,叫做这个数的小和,求一个数组的小和
  6. */
  7. public class SmallSum {
  8. public static void main(String[] args) {
  9. Scanner sc = new Scanner(System.in);
  10. while (sc.hasNext()) {
  11. String[] str = sc.nextLine().split(",");
  12. int[] num = new int[str.length];
  13. for (int i = 0; i < str.length; i++) {
  14. num[i] = Integer.parseInt(str[i]);
  15. }
  16. int result = smallSum(num);
  17. System.out.println(result);
  18. }
  19. sc.close();
  20. }
  21. private static int smallSum(int[] num) {
  22. if (num == null || num.length < 2)
  23. return 0;
  24. return mergeSort(num, 0, num.length - 1);
  25. }
  26. private static int mergeSort(int[] num, int L, int R) {
  27. //结束条件
  28. if (L == R) {
  29. return 0;
  30. }
  31. //计算中点位置
  32. //防止溢出
  33. int mid = L + ((R - L) >> 1);
  34. //左边产生的小和+右边陈胜的小和+合并产生的小和就是整个数组的小和
  35. return mergeSort(num, L, mid) + mergeSort(num, mid + 1, R) + merge(num, L, mid, R);
  36. }
  37. private static int merge(int[] num, int l, int mid, int r) {
  38. //辅助数组
  39. int[] temp = new int[r - l + 1];
  40. //辅助数组下标
  41. int i = 0;
  42. //左半边数组的指针
  43. int p1 = l;
  44. //右半边数组的指针
  45. int p2 = mid + 1;
  46. //小和
  47. int res = 0;
  48. while (p1 <= mid && p2 <= r) {
  49. //如果左边指向的值小于右边指向的值,那么p1位置的值一定小于p2以后的所有值
  50. //因为是有序的,这时候产生小和
  51. if (num[p1]<num[p2]){
  52. //计算小和
  53. res = res+num[p1]*(r-p2+1);
  54. //排序过程
  55. temp[i++] = num[p1++];
  56. }else {
  57. //不产生小和
  58. res = res+0;
  59. //排序过程
  60. temp[i++] = num[p2++];
  61. }
  62. }
  63. //p1没有越界,说明p2越界了,将左边剩余元素拷贝到辅助数组
  64. while (p1 <= mid) {
  65. temp[i++] = num[p1++];
  66. }
  67. //p2没有越界,说明p1越界了
  68. while (p2 <= r) {
  69. temp[i++] = num[p2++];
  70. }
  71. //将临时数组中的内容拷贝回原数组中
  72. //(原left-righe范围的内容被复制回原数组)
  73. for (int j = 0; j < temp.length; j++) {
  74. num[l + j] = temp[j];
  75. }
  76. return res;
  77. }
  78. }

逆序对问题:

在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,请打印所有的逆序对。

主要思想:

在归并的过程中比较,找出左边有多少数比右边的数大,有则产生逆序对,打印。

实现代码(Java):

  1. package NewCoder;
  2. import java.util.Scanner;
  3. /**
  4. * 逆序对问题
  5. * 在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,请打印所有逆序对。
  6. */
  7. public class Reverse {
  8. public static int count = 0;
  9. public static void main(String[] args){
  10. Scanner sc = new Scanner(System.in);
  11. while (sc.hasNext()){
  12. String[] str = sc.nextLine().split(",");
  13. int[] num = new int[str.length];
  14. for (int i = 0; i < str.length; i++) {
  15. num[i] = Integer.parseInt(str[i]);
  16. }
  17. reverse(num);
  18. System.out.println(count);
  19. }
  20. sc.close();
  21. }
  22. private static void reverse(int[] num) {
  23. if (num==null||num.length<2){
  24. return;
  25. }
  26. mergeSort(num,0,num.length-1);
  27. }
  28. private static void mergeSort(int[] num, int l, int r) {
  29. if (l==r){
  30. return;
  31. }
  32. int mid = l+((r-l)>>1);
  33. //打印左边合并产生的逆序对
  34. mergeSort(num,l,mid);
  35. //打印右边合并产生的逆序对
  36. mergeSort(num,mid+1,r);
  37. //打印整体合并产生的逆序对
  38. merge(num,l,mid,r);
  39. }
  40. private static void merge(int[] num, int l, int mid, int r) {
  41. int[] temp = new int[r-l+1];
  42. int i = 0;
  43. int p1 = l;
  44. int p2 = mid+1;
  45. while (p1<=mid&&p2<=r){
  46. //如果p1元素大于p2元素,那么左半边元素一定都大于p1元素
  47. if (num[p1]>num[p2]){
  48. //p2以后的逆序对元素全部打印出来
  49. for (int j = p2; j <=r ; j++) {
  50. System.out.println(num[p1]+""+num[j]);
  51. }
  52. //计算数量
  53. count+=(r-p2+1);
  54. temp[i++]=num[p1++];
  55. }else {
  56. temp[i++]=num[p2++];
  57. }
  58. }
  59. while (p1<=mid){
  60. temp[i++]=num[p1++];
  61. }
  62. while (p2<=r){
  63. temp[i++]=num[p2++];
  64. }
  65. for (int j = 0; j < temp.length; j++) {
  66. num[l+j] = temp[j];
  67. }
  68. }
  69. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/227511
推荐阅读
相关标签
  

闽ICP备14008679号