Bootstrap

LCR.170 逆序对的数量 (归并排序)

归并排序模板 好理解版

class MergeSortTemplate {
    public void mergeSort(int[] nums) {
        int len = nums.length;
        if (len < 2) {
            return;
        }
        int[] temp = new int[len]; // 临时数组,用于合并
        divideAndMerge(nums, 0, len - 1, temp);
    }

    private void divideAndMerge(int[] nums, int left, int right, int[] temp) {
        if (left >= right) {
            return; // 只有一个元素时直接返回
        }

        int mid = left + (right - left) / 2;

        // 递归处理左半部分
        divideAndMerge(nums, left, mid, temp);

        // 递归处理右半部分
        divideAndMerge(nums, mid + 1, right, temp);

        // 如果已经有序,无需合并
        if (nums[mid] <= nums[mid + 1]) {
            return;
        }

        // 合并两个有序部分
        merge(nums, left, mid, right, temp);
    }

    private void merge(int[] nums, int left, int mid, int right, int[] temp) {
        // 拷贝当前区间到辅助数组
        for (int i = left; i <= right; i++) {
            temp[i] = nums[i];
        }

        int i = left;      // 左子数组起点
        int j = mid + 1;   // 右子数组起点
        int k = left;      // 合并数组起点

        // 合并两个有序区间
        while (i <= mid && j <= right) {
            if (temp[i] <= temp[j]) {
                nums[k++] = temp[i++];
            } else {
                nums[k++] = temp[j++];
            }
        }

        // 左子数组剩余部分
        while (i <= mid) {
            nums[k++] = temp[i++];
        }

        // 右子数组剩余部分
        while (j <= right) {
            nums[k++] = temp[j++];
        }
    }

    public static void main(String[] args) {
        int[] nums = {9, 7, 5, 3, 1, 2, 4, 6, 8};
        MergeSortTemplate sort = new MergeSortTemplate();
        sort.mergeSort(nums);
        for (int num : nums) {
            System.out.print(num + " ");
        }
    }
}

这道题

 

class Solution {
    public int reversePairs(int[] nums) {
        int len = nums.length;
        if (len < 2) {
            return 0;
        }
        int[] temp = new int[len];
        return reverse(nums, 0, len - 1, temp);
    }
    private int reverse(int[] nums, int left, int right, int[] temp) {
        if (left == right) {
            return 0;
        }
        int mid = left + (right - left) / 2;

        // 左右子数组的逆序对数量
        int leftPairs = reverse(nums, left, mid, temp);
        int rightPairs = reverse(nums, mid + 1, right, temp);

        // 如果两部分已经有序,则无需统计跨区间逆序对
        if (nums[mid] <= nums[mid + 1]) {
            return leftPairs + rightPairs;
        }

        // 跨区间逆序对数量
        int crossPairs = mergeAndCount(nums, left, mid, right, temp);
        return leftPairs + rightPairs + crossPairs;
    }

    private int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
        for (int i = left; i <= right; i++) {
            temp[i] = nums[i];
        }

        int i = left;      // 左子数组的起始指针
        int j = mid + 1;   // 右子数组的起始指针
        int count = 0;

        int m = left;      // 合并的数组索引
        while (i <= mid && j <= right) {
            if (temp[i] <= temp[j]) {
                nums[m++] = temp[i++];
            } else {
                nums[m++] = temp[j++];
                // 统计逆序对数量
                count += (mid - i + 1); // 左子数组中,从 i 到 mid 的元素都大于 temp[j]
            }
        }

        // 将左子数组剩余元素拷贝回去
        while (i <= mid) {
            nums[m++] = temp[i++];
        }

        // 将右子数组剩余元素拷贝回去
        while (j <= right) {
            nums[m++] = temp[j++];
        }

        return count;
    }
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;