整体是递归分治的思想:左边排好序 + 右边排好序 + merge让整体有序。一般我们会暴力破解O(N²)的算法,如果进一步优化:就是可以利用上次计算的结果,不重复计算,不回退 这样的方案。

归并排序算法

  1. package B2_lx.mytx.class04;
  2. import java.util.Arrays;
  3. /**
  4. * @title: Algorithm
  5. * @description: 递归
  6. * @author:
  7. * @date: 2022/07/03 05:02
  8. */
  9. public class Code01_MergeSort {
  10. public static void mergeSort(int[] arr){
  11. if (null ==arr || arr.length<2){
  12. return;
  13. }
  14. process(arr,0, arr.length-1);
  15. }
  16. public static void process(int[] arr,int L, int R){
  17. if (L == R){
  18. return;
  19. }
  20. int mid = L + ((R - L) >>1);
  21. process(arr,L,mid);
  22. process(arr,mid+1,R);
  23. merge(arr,L,R,mid);
  24. }
  25. public static void merge(int[] arr, int L, int R, int M){
  26. int[] help = new int[R-L+1];
  27. int i = 0;
  28. int p1 = L;
  29. int p2 = M + 1;
  30. while (p1 <=M && p2 <= R){
  31. if (arr[p1] <= arr[p2]){
  32. help[i] = arr[p1];
  33. i++;
  34. p1++;
  35. }else {
  36. help[i] = arr[p2];
  37. i++;
  38. p2++;
  39. }
  40. //help[i++] = arr[p1] >= arr[p2] ? arr[p1++] : arr[p2++];
  41. }
  42. while (p1 <= M){
  43. help[i] = arr[p1];
  44. i++;
  45. p1++;
  46. }
  47. while (p2 <= R){
  48. help[i] = arr[p2];
  49. i++;
  50. p2++;
  51. }
  52. for (int j = 0; j < help.length; j++) {
  53. arr[L + j] = help[j];
  54. }
  55. System.out.println(Arrays.toString(help));
  56. }
  57. public static void main(String[] args) {
  58. int[] arr = new int[]{8,3,5,2,7,4,9,1,6};
  59. mergeSort(arr);
  60. System.out.println(Arrays.toString(arr));
  61. }
  62. }

小和问题

在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。求数组小和。 例子: [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

  1. package B2_lx.mytx.class04;
  2. /**
  3. * @title: Algorithm
  4. * @description: 小和问题
  5. * @author: 北京小桔汇金网络科技有限公司
  6. * @date: 2022/07/06 23:23
  7. */
  8. public class Code02_SmallSum {
  9. public static Integer process(Integer[] arr,int L,int R){
  10. if (L == R){
  11. return 0;
  12. }
  13. int mid = L + ((R - L)>>1);
  14. return process(arr,L,mid) +
  15. process(arr,mid +1, R) +
  16. merge(arr,L,R,mid);
  17. }
  18. public static Integer merge(Integer[] arr,int L,int R,int mid){
  19. Integer[] help = new Integer[R-L+1];
  20. int i = 0;
  21. int p1 = L;
  22. int p2 = mid +1;
  23. int result = 0;
  24. while (p1 <= mid && p2 <=R){
  25. result += arr[p1] < arr[p2] ? arr[p1] * (R-p2+1) :0;
  26. help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
  27. //if (arr[p1] <= arr[p2]){
  28. // help[i] = arr[p1];
  29. // i++;
  30. // p1++;
  31. //}else {
  32. // help[i] = arr[p2];
  33. // i++;
  34. // p2++;
  35. //}
  36. }
  37. while (p1 <=mid){
  38. help[i++] = arr[p1++];
  39. }
  40. while ((p2 <=R)){
  41. help[i++] = arr[p2++];
  42. }
  43. for (i = 0; i < help.length; i++) {
  44. arr[L+i] = help[i];
  45. }
  46. return result;
  47. }
  48. public static void main(String[] args) {
  49. Integer[] arr = new Integer[]{1,3,4,2,5};
  50. System.out.println(process(arr,0,4));;
  51. }
  52. }

逆序对问题

在一个数组中, 任何一个前面的数a,和任何一个后面的数b, 如果(a,b)是降序的,就称为逆序对 返回数组中所有的逆序对

  1. package B2_lx.mytx.class04;
  2. /**
  3. * @title: Algorithm
  4. * @description: 逆序对
  5. * @author: 北京小桔汇金网络科技有限公司
  6. * @date: 2022/07/07 15:44
  7. */
  8. public class Code03_ReversePair {
  9. public static int reversePair(int[] arr){
  10. if (null == arr || arr.length <2){
  11. return 0;
  12. }
  13. return process(arr,0,arr.length -1);
  14. }
  15. public static int process(int[] arr, int L, int R){
  16. if (L == R){
  17. return 0;
  18. }
  19. int mid = L + ((R - L)>>1);
  20. return process(arr,L,mid) + process(arr,mid+1, R) + merge(arr,L,mid,R);
  21. }
  22. public static int merge(int[] arr,int L, int mid, int R){
  23. int[] help = new int[R -L +1];
  24. int i = help.length -1;
  25. int p1 = mid;
  26. int p2 = R;
  27. int result = 0;
  28. while (p1 >=L && p2 > mid){
  29. /*if (arr[p1] <= arr[p2]){
  30. help[i] = arr[p2];
  31. i--;
  32. p2 --;
  33. } else {
  34. help[i] = arr[p1];
  35. i--;
  36. p1 --;
  37. result = result + (p2 - mid);
  38. }*/
  39. result += arr[p1] > arr[p2] ? (p2 - mid) : 0;
  40. help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];
  41. }
  42. while (p1>=L){
  43. help[i--] = arr[p1--];
  44. }
  45. while (p2 >mid){
  46. help[i--] = arr[p2--];
  47. }
  48. for ( i = 0; i < help.length; i++) {
  49. arr[L+i] = help[i];
  50. }
  51. return result;
  52. }
  53. public static void main(String[] args) {
  54. int[] arr = new int[]{3,5,1,2,6,4,9,7};
  55. System.out.println(reversePair(arr));
  56. }
  57. }

大于两倍问题

求任何一个位置上的子数组(可以利用前缀和) 在一个数组中, 对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数 比如:[3,1,7,0,2] 3的后面有:1,0 1的后面有:0 7的后面有:0,2 0的后面没有 2的后面没有 所以总共有5个

package B2_lx.mytx.class04;

/**
 * @title: Algorithm
 * @description: 在一个数组中,对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数
 * @author: 北京小桔汇金网络科技有限公司
 * @date: 2022/07/08 09:55
 */
public class Code04_BiggerThanRightTwice {
    public static Integer biggerThanRightTwice(int[] arr){
        if (null == arr || arr.length<2){
            return 0;
        }
        return process(arr,0,arr.length-1);
    }
    public static int process(int[] arr,int l, int r){
        if (l == r ){
            return 0;
        }
        int m = l + ((r-l)>>1);
        return process(arr,l,m) + process(arr,m+1,r) + merge(arr,l,r,m);
    }
    public static int merge(int[] arr,int l,int r,int m){
        //分成2步,先merge计算出 右边有几个数,乘2后仍然小于 它。
        int winR = m+1;
        int result = 0;
        for (int i = l; i<=m; i++){
            while (winR <=r && arr[i] > (arr[winR] * 2)){
                winR ++;
            }
            result += winR - (m +1);
        }
        // 这里无需merge排序,不需要归并算法的排序操作
        /*int[] help = new int[r-l+1];
        int i = 0;
        int p1 = l;
        int p2 = m+1;
        while (p1 <= m && p2 <= r){
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++] ;
        }
        while (p1 <=m){
            help[i++] = arr[p1++];
        }
        while (p2 <= r){
            help[i++] = arr[p2++];
        }

        for (int j = 0; j< help.length; j++){
            arr[l+j] = help[j];
        }*/
        return result;
    }
    public static void main(String[] args) {
        int[] arr = new int[]{3,1,7,0,2};
        System.out.println(biggerThanRightTwice(arr));
    }
}