算法课笔记-归并排序解决小和问题和逆序对问题

算法课笔记

第一次课

归并排序

  • 指针正着排

  • package com.LeetCode.day02.demo02;
    
    import java.lang.reflect.Array;
    import java.util.Arrays;
    
    public class MergeSort {
    
        public static void mergeSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            mergeSort(arr, 0, arr.length - 1);
        }
    
    
        public static void mergeSort(int[] arr, int L, int R) {
            if (L == R) {
                return;
            }
            int mid = L + ((R - L) >> 1);
            mergeSort(arr, L, mid);
            mergeSort(arr, mid + 1, R);
            merge(arr, L, mid, R);
        }
    
      // 归并函数
        public static void merge(int[] arr, int L, int mid, int R) {
            int[] help = new int[R - L + 1];
            int i = 0;
            int p1 = L;
            int p2 = mid + 1;
    
          // 先把小的数放在数组最前面
            while (p1 <= mid && p2 <= R) {
                help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
            }
    
            while (p1 <= mid) {
                help[i++] = arr[p1++];
            }
    
            while (p2 <= R) {
                help[i++] = arr[p2++];
            }
          
          // 拷贝help数组中的元素到arr数组中
            for (i = 0; i < help.length; i++) {
                arr[L + i] = help[i];
            }
    
            System.out.println(Arrays.toString(help));
        }
    
    
        public static void main(String[] args) {
            int a[] = new int[]{7,5,1,6,4};
            mergeSort(a);
            System.out.println(Arrays.toString(a));
        }
    }
    
    
  • 指针倒着排

  • package com.LeetCode.day02.demo02;
    
    import java.util.Arrays;
    
    public class mergeSort3 {
        public static void mergeSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
    
            mergeSort(arr, 0, arr.length - 1);
        }
    
    
        public static void mergeSort(int[] arr, int L, int R) {
            if (L == R) {
                return;
            }
    
            int mid = L + ((R - L) >> 1);
            mergeSort(arr, L, mid);
            mergeSort(arr, mid + 1, R);
            merge(arr, L, mid, R);
        }
    
      // 归并函数
        public static void merge(int[] arr, int L, int mid, int R) {
            int[] help = new int[arr.length];
            int i = R;
            int p1 = mid;
            int p2 = R;
    
          // 先把大的数放在数组最后面
            while (p1 >= L && p2 >= mid+1) {
                help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];
            }
    
            while (p1 >= L) {
                help[i--] = arr[p1--];
            }
    
            while (p2 >= mid+1) {
                help[i--] = arr[p2--];
            }
    
            // 拷贝help数组到arr数组
            while(L<=R){
                arr[L]=help[L++];
            }
            //System.out.println(Arrays.toString(help));
        }
    
        public static void main(String[] args) {
            int a[] = new int[]{7, 5, 1, 6, 4};
            mergeSort(a);
            System.out.println(Arrays.toString(a));
        }
    }
    
    
  • 归并排序的练习

    (1)小和问题

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

    的小和。

    例子:

    [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

    package com.LeetCode.day02.demo02;
    
    import java.lang.reflect.Array;
    import java.util.Arrays;
    
    public class smallSum {
        public static int smallSum(int[] arr, int L, int R) {
            if (L == R) {
                return 0;
            }
            int mid = L + (R - L) / 2;
    
            return smallSum(arr, L, mid) + smallSum(arr, mid + 1, R) + merge(arr, L, mid, R);
        }
    
        public static int merge(int[] arr, int L, int mid, int R) {
            int[] help = new int[R - L + 1];
            int i = 0;
            int p1 = L;
            int p2 = mid + 1;
            int res = 0;
            while (p1 <= mid && p2 <= R) {
              // 如果左边数组的当前指针指向的数比右边数组的当前指针指向的数小 那么右边数组中所有数都比左边这个数大,所以有(R - p2 + 1) * arr[p1]
                res += arr[p1] < arr[p2] ? (R - p2 + 1) * arr[p1] : 0;
                help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
            }
    
            while (p1 <= mid) {
                help[i++] = arr[p1++];
            }
            while (p2 <= R) {
                help[i++] = arr[p2++];
            }
    
            for (i = 0; i < help.length; i++) {
                arr[L + i] = help[i];
            }
    
            return res;
        }
    
        public static void main(String[] args) {
            int[] arr = new int[]{1, 3, 4, 2, 5};
            int result = smallSum(arr,0,arr.length-1);
            System.out.println(result);
    //        System.out.println(Arrays.toString(arr));
        }
    }
    

    (2)逆序对问题

    在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数

    例如在数组[4,5,8,3,2,1]
    全部逆序对:(3,2)(3,1)(2,1)(8,3)(8,2)(8,1)(5,3)(5,2)(5,1)(4,3)(4,2)(4,1) 一共 12个

    package com.LeetCode.day02.demo02;
    
    import java.util.Arrays;
    
    public class nixudui {
    
        public static int reverseCp(int[] arr, int L, int R) {
            if (arr == null || arr.length < 2) {
                return 0;
            }
            if (L == R) {
                return 0;
            }
    
            int mid = L + (R - L) / 2;
    
            return reverseCp(arr, L, mid)
                    + reverseCp(arr, mid + 1, R)
                    + merge(arr, L, mid, R);
        }
    
        public static int merge(int[] arr, int L, int mid, int R) {
            int[] help = new int[arr.length];
            int i = R;
            int p1 = mid;
            int p2 = R;
            int res = 0;
            while (p1 >= L && p2 >= mid + 1) {
                //res += arr[p1] > arr[p2] ? (p2-mid) : 0;
                if(arr[p1] > arr[p2]){
                    res+=(p2-mid);
                  // 打印所有逆序对
                    for(int j = p2;j>=mid+1;j--){
                        System.out.println("("+arr[p1]+","+arr[j]+")" );
                    }
                }
    
    
                help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];
            }
            while (p1 >= L) {
                help[i--] = arr[p1--];
            }
            while (p2 >= mid + 1) {
                help[i--] = arr[p2--];
            }
    
            while(L<=R){
                arr[L]=help[L++];
            }
    
            return res;
        }
    
    
        public static void main(String[] args) {
    //        int test[] = {7, 5, 1, 6, 4};
            int test[] = {4,5,8,3,2,1};
            int result = reverseCp(test, 0, test.length - 1);
            System.out.println(result);
            System.out.println(Arrays.toString(test));
        }
    }
    
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值