欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

小和问题(归并排序)

程序员文章站 2022-05-04 08:49:40
题目在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和。描述:[1, 3, 2, 51, 5]1左边比1小的数 0;3左边比3小的数 1;2左边比2小的数 1;51左边比51小的数 2,3,1;5左边比5小的数 2,3,1;所以小和为0+1+1+2+3+1+2+3+1=14;解题思路转换思想:上述例子我们要求5左面比5小的所有数的和可以转换成 :求1右面比1大的数的个数×1本身+3右面比3大的数个数×3本身**+2右...

题目

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

描述:
[1, 3, 2, 51, 5]
1左边比1小的数 0;
3左边比3小的数 1;
2左边比2小的数 1;
51左边比51小的数 2,3,1;
5左边比5小的数 2,3,1;
所以小和为0+1+1+2+3+1+2+3+1=14;

解题思路

转换思想:上述例子我们要求5左面比5小的所有数的和可以转换成 :
求1右面比1大的数的个数×1本身+3右面比3大的数个数×3本身**+2右面比2大的数的个数×2本身+51右面比51大的数的个数×51本身+5右面比5大的数的个数×**5本身。

如何理解?
上述例子中从1开始遍历求到5计算小和,那么1总共被加了4次因为3比1大,2比1大,51比1大,5比1大, 所以就是1*4;同理每个元素的小和就是本身×后面比他大的个数,之后加起来就是最终答案。

如此一来问题转换为:
[1, 3, 2, 51, 5]
1右边比1大的个数本身 4×1=4;
3右边比3大的个数
本身 3×2=6;
2右边比2大的个数本身 2×2=4;
51右边比51大的个数
本身 5×1=0;
5右边比5大的个数*本身 5×0=0;
所以小和为4+6+4+0+0=14;

解决方案

暴力破解这里就不说了,双层for循环遍历判断右面数比左面大就计数++,时间复杂度为o(n的平方)。
本题还可以用归并排序处理。时间复杂度为o(n×logn)

在并的时候判断以上逻辑并且累加即可。

代码如下:


public class Main {
    private static int sum = 0;

    public static void main(String[] args) {
        int[] arr = {1, 3, 2, 51, 5};
        mergeSort(arr, 0, arr.length - 1);
        print_nums(arr);
        System.out.println();
        System.out.println(sum);
    }

    public static void mergeSort(int[] arr, int l, int r) {
        if (l == r) {
            return;
        }
        int mid = l + (r - l) / 2;
        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 pl = l;
        int pr = mid + 1;
        int i = 0;
        while (pl <= mid && pr <= r) {
            sum += arr[pl] < arr[pr] ? (r - pr + 1) * arr[pl] : 0;
            help[i++] = arr[pl] < arr[pr] ? arr[pl++] : arr[pr++];
        }
        while (pl <= mid) {
            help[i++] = arr[pl++];
        }
        while (pr <= r) {
            help[i++] = arr[pr++];
        }
        for (i = 0; i < help.length; i++) {
            arr[l + i] = help[i];
        }
    }

    public static void print_nums(int[] nums) {
        for (int i : nums) {
            System.out.print(i + " ");
        }
    }


}


同理也可以求数列的逆序数


/**
 * 数列逆序数 并输出是奇排列还是偶排列
 */
public class Main {
    private static int sum = 0;

    public static void main(String[] args) {
        int[] nums = {2,4,3,1};
        MergeSort(nums, 0, nums.length - 1);
       /* print_nums(nums);*/
        String s = checkIsEvenNumber(sum);
        System.out.println(s + ":" + sum);
    }

    public static void MergeSort(int[] nums, int l, int r) {
        if (l == r) {
            return;
        }
        int mid = l + ((r - l) >> 1);
        MergeSort(nums, l, mid);
        MergeSort(nums, mid + 1, r);
        Merge(nums, l, mid, r);
    }

    public static void Merge(int[] nums, int l, int mid, int r) {
        int[] help = new int[r - l + 1];
        int pl = l;
        int pr = mid + 1;
        int i = 0;
        while (pl <= mid && pr <= r) {
            sum += nums[pl] > nums[pr] ? (r - pr + 1) : 0;
            help[i++] = nums[pl] > nums[pr] ? nums[pl++] : nums[pr++];
        }
        while (pl <= mid) {
            help[i++] = nums[pl++];
        }
        while (pr <= r) {
            help[i++] = nums[pr++];
        }
        for (i = 0; i < help.length; i++) {
            nums[l + i] = help[i];
        }
    }

    public static String checkIsEvenNumber(int num) {
        return num % 2 == 0 ? "偶排列" : "奇排列";
    }

  /*  public static void print_nums(int[] nums) {
        for (int i : nums) {
            System.out.print(i + " ");
        }
    }*/


}


本文地址:https://blog.csdn.net/qq_35416214/article/details/107475524