2.<tag-排序和归并排序巧妙解题>-剑指 Offer 51. 数组中的逆序对 + 补充题-计算数组的小和

剑指 Offer 51. 数组中的逆序对

[案例需求]
在这里插入图片描述

[思路分析]

还有以下解法等待补充:

  1. 有序数组 (Sorted List)
  2. 归并排序 (Merge Sort)
  3. 树状数组 (Binary Indexed Tree)
  4. 线段树 (Segment Tree)

[代码实现]

class Solution {
    int count = 0;
    public int reversePairs(int[] nums) {
        int len = nums.length;
        mergeSort(nums, 0, len -1);
        return count;
    }

    //分
    public void mergeSort(int[] nums, int left, int right){
        if(left >= right)return;

        int mid = left + ((right - left) >> 1);
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);

        sort(nums, left, mid, right);
    }

    //治
    public void sort(int[] nums, int left, int mid, int right){
        int[] res = new int[right - left + 1];
        int index = 0;

        int L = left, R = mid + 1;

        // L--> mid,   R-->right
        while(L <= mid && R <= right){
            if(nums[L] > nums[R]){
                count += (mid - L + 1); //
                res[index++] = nums[R++];
            }else{
                res[index++] = nums[L++];
            }
        }

        while(L <= mid)res[index++] = nums[L++];
        while(R <= right)res[index++] = nums[R++];

        for(int i = 0; i < index; i++){
            nums[i + left] = res[i];
        }
    }
}

在这里插入图片描述

补充题-计算数组的小和

[案例需求]
在这里插入图片描述

[思路分析] (cv得来的, 还需要深入

归并排序的应用,当归并过程中发现左边的数小于右边的数,即得到一组小和。如1 3 5 7 和 2 4 6 8,当左边遍历第一个数,有1 < 2,则1也小于2右边的所有数,即这组小和为1*4。

  • 整个数组的小和=数组左半部分贡献的小和+数组右半部分贡献的小和+左右两部分之间贡献的小和

参考文章:

  1. https://mp.weixin.qq.com/s/rMsbcUf9ZPhvfRoyZGW6HA
  2. 点我
    [代码实现]
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int len = in.nextInt();
        int[] nums = new int[len];
        for (int i = 0; i < len; i++) {
            nums[i] = in.nextInt();
        }

        System.out.println(mergeSort(nums, 0, nums.length - 1, new int[nums.length]));
    }

    public static long mergeSort(int[] nums, int left, int right, int[] temp) {
        if (left >= right) {
            return 0;
        }

        int mid = left + (right - left) / 2;
        long leftTempSum = mergeSort(nums, left, mid, temp);
        long rightTempSum = mergeSort(nums, mid + 1, right, temp);
        long curTempSum = merge(nums, left, mid, right, temp);

        return leftTempSum + rightTempSum + curTempSum;
    }

    // 合并 nums[left:mid] nums[mid + 1:right] 这两段有序数组
    public static long merge(int[] nums, int left, int mid, int right, int[] temp) {
        int i = left, j = mid + 1, t = 0;
        long tempSum = 0;

        while (i <= mid && j <= right) {
            if (nums[i] <= nums[j]) {
                // 由于左右子数组均有序,所以 nums[i] 比 nums[j:right] 这些元素都要小,所以 nums[i] “产生” 的小和为 nums[i] * (right - j + 1)
                tempSum += nums[i] * (right - j + 1);
                temp[t++] = nums[i++];
            } else {
                temp[t++] = nums[j++];
            }
        }

        while (i <= mid) {
            temp[t++] = nums[i++];
        }

        while (j <= right) {
            temp[t++] = nums[j++];
        }

        t = 0;//temp ***有 right - left + 1 个元素
        while (left <= right) {
            nums[left++] = temp[t++];
        }

        return tempSum;
    }

}
posted @   青松城  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示