算法奇妙屋(四)-归并分治

文章目录

  • [一. 力扣 912. 排序数组](#一. 力扣 912. 排序数组)
    • [1. 题目](#1. 题目)
    • [2. 算法原理](#2. 算法原理)
    • 3.代码
  • [二. 力扣 LCR 170. 交易逆序对的总数](#二. 力扣 LCR 170. 交易逆序对的总数)
    • [1. 题目](#1. 题目)
    • [2. 算法原理](#2. 算法原理)
      • [(1) 方法一](#(1) 方法一)
      • [(2) 方法二](#(2) 方法二)
    • [3. 代码](#3. 代码)
      • [(1) 方法一代码:](#(1) 方法一代码:)
      • [(2) 方法二代码:](#(2) 方法二代码:)
  • [三. 力扣 315. 计算右侧小于当前元素的个数](#三. 力扣 315. 计算右侧小于当前元素的个数)
    • [1. 题目](#1. 题目)
    • [2. 算法原理](#2. 算法原理)
    • [3. 代码](#3. 代码)
  • [四. 力扣 493. 翻转对](#四. 力扣 493. 翻转对)
    • [1. 题目](#1. 题目)
    • [2. 算法原理](#2. 算法原理)
      • [(1) 方法一(降序):](#(1) 方法一(降序):)
      • [(2) 方法二(升序):](#(2) 方法二(升序):)
    • [3. 代码](#3. 代码)
      • [(1) 方法一(降序)代码:](#(1) 方法一(降序)代码:)
      • [(2) 方法二(升序)代码:](#(2) 方法二(升序)代码:)

这个篇章我们基于归并排序,并结合分治思想来解决问题

一. 力扣 912. 排序数组

1. 题目

2. 算法原理

归并排序我们应该不陌生, 这里我们只是复习归并排序的算法原理

3.代码

java 复制代码
    public int[] sortArray(int[] nums) {
        mergeSort(nums,0,nums.length-1);
        return nums;
    }
    public void mergeSort(int[] nums, int s, int e) {
        if (s >= e) {
            return;
        }
        int mid = (s + e) / 2;
        // 递归左区间
        mergeSort(nums,s,mid);
        // 递归右区间
        mergeSort(nums,mid + 1,e);

        // 递归完成后, 给两个数组排序(数组并不是真实数组,而是可以看成两个数组)
        int left1 = s;
        int left2 = mid + 1;
        int i = 0;
        int[] tmp = new int[e - s + 1];
        while (left1 <= mid && left2 <= e) {
            if (nums[left1] <= nums[left2]) {
                tmp[i++] = nums[left1++];
            }else {
                tmp[i++] = nums[left2++];
            }
        }
        while(left1 <= mid) {
            tmp[i++] = nums[left1++];
        }
        while(left2 <= e) {
            tmp[i++] = nums[left2++];
        }
        // 将tmp数组的值放入nums中
        for (int j = 0; j < e - s + 1; j++) {
            nums[j + s] = tmp[j];
        }

    }

二. 力扣 LCR 170. 交易逆序对的总数

1. 题目

2. 算法原理

(1) 方法一

(2) 方法二

3. 代码

(1) 方法一代码:

java 复制代码
    int ret = 0;
    int[] tmp ;
    public int reversePairs(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums, 0,nums.length - 1);
        return ret;
    }
    public void mergeSort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = (end + start) / 2;
        // 递归左面[s,mid]
        mergeSort(nums, start, mid);
        // 递归右面[mid+1,e]
        mergeSort(nums, mid + 1, end);
        // 递归结束, 开始排序, 并统计
        int left1 = start;
        int left2 = mid + 1;
        int i = 0;
        while (left1 <= mid && left2 <= end) {
            if (nums[left1] <= nums[left2]) {
                tmp[i++] = nums[left1++];
            }else {
                ret += mid - left1 + 1;
                tmp[i++] = nums[left2++];
            }
        }
        while (left1 <= mid) {
            tmp[i++] = nums[left1++];
        }
        while (left2 <= end) {
            tmp[i++] = nums[left2++];
        }
        for (int j = 0; j < end - start + 1; j++) {
            nums[j + start] = tmp[j];
        }
    }

(2) 方法二代码:

java 复制代码
    int ret = 0;
    int[] tmp ;
    public int reversePairs(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums, 0,nums.length - 1);
        return ret;
    }
    public void mergeSort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = (end + start) / 2;
        // 递归左面[s,mid]
        mergeSort(nums, start, mid);
        // 递归右面[mid+1,e]
        mergeSort(nums, mid + 1, end);
        // 递归结束, 开始排序, 并统计
        int left1 = start;
        int left2 = mid + 1;
        int i = 0;
        while (left1 <= mid && left2 <= end) {
            if (nums[left1] <= nums[left2]) {
                tmp[i++] = nums[left2++];
            }else {
                ret += end - left2 + 1;
                tmp[i++] = nums[left1++];
            }
        }
        while (left1 <= mid) {
            tmp[i++] = nums[left1++];
        }
        while (left2 <= end) {
            tmp[i++] = nums[left2++];
        }
        for (int j = 0; j < end - start + 1; j++) {
            nums[j + start] = tmp[j];
        }
    }

三. 力扣 315. 计算右侧小于当前元素的个数

1. 题目

2. 算法原理

3. 代码

java 复制代码
    int[] tmpNums;
    int[] tmpIndex;
    int[] index;
    int[] ret;
    public List<Integer> countSmaller(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int n = nums.length;
        tmpNums = new int[n];
        tmpIndex = new int[n];
        index = new int[n];
        ret = new int[n];
        for (int i = 0; i < n; i++) {
            index[i] = i;
        }
        mergeSort(nums, 0, n - 1);
        for (int x : ret) {
            list.add(x);
        }
        return list;
    }
    public void mergeSort(int[] nums, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = (start + end) / 2;
        // 计算左面个数
        mergeSort(nums, start, mid);
        // 计算右面个数
        mergeSort(nums, mid + 1, end);
        // 计算一左一右
        int left1 = start;
        int left2 = mid + 1;
        int i = 0;
        while (left1 <= mid && left2 <= end) {
            if (nums[left1] <= nums[left2]) {
                tmpNums[i] = nums[left2];
                tmpIndex[i++] = index[left2++];
            }else {
                ret[index[left1]] += end - left2 + 1;
                tmpNums[i] = nums[left1];
                tmpIndex[i++] = index[left1++];
            }
        }
        while (left1 <= mid) {
            tmpNums[i] = nums[left1];
            tmpIndex[i++] = index[left1++];
        }
        while (left2 <= end) {
            tmpNums[i] = nums[left2];
            tmpIndex[i++] = index[left2++];
        }
        // 将tmp数组的值放回到原数组其中, 排序工作
        for (int j = start; j <= end; j++) {
            nums[j] = tmpNums[j - start];
            index[j] = tmpIndex[j - start];
        }

    }

四. 力扣 493. 翻转对

1. 题目

题目意思大白话解释就是前面有多少数大于后面数值的2倍

2. 算法原理

(1) 方法一(降序):

(2) 方法二(升序):

3. 代码

(1) 方法一(降序)代码:

我们要注意,这道题里面的测试用例输入数组中的所有数字都在32位整数的表示范围内, 但是我们×2后那么就会超出32位, 所以我们用除以2的方式

java 复制代码
    int[] tmp;
    public int reversePairs(int[] nums) {
        int n = nums.length;
        tmp = new int[n];
        return mergeSort(nums, 0, n - 1);
    }


    public int mergeSort(int[] nums, int start, int end) {
        if (start >= end) {
            return 0;
        }
        int ret = 0;
        int mid = (start + end) / 2;
        // 先计算左面
        ret += mergeSort(nums, start, mid);
        // 再计算右面
        ret += mergeSort(nums, mid + 1, end);
        // 最后计算一左一右
        int left1 = start;
        int left2 = mid + 1;
        while (left1 <= mid && left2 <= end) {
            if (nums[left1] / 2.0 >  nums[left2]) {
                ret += end - left2 + 1;
                left1++;
            }else {
                left2++;
            }
        }
        // 放入tmp中排序
        left1 = start;
        left2 = mid + 1;
        int i = 0;
        while (left1 <= mid && left2 <= end) {
            tmp[i++] = nums[left1] > nums[left2] ? nums[left1++] : nums[left2++];
        }
        while (left1 <= mid) {
            tmp[i++] = nums[left1++];
        }
        while (left2 <= end) {
            tmp[i++] = nums[left2++];
        }
        // 合并数组
        for (int j = start; j <= end; j++) {
            nums[j] = tmp[j - start];
        }
        return ret;
    }

(2) 方法二(升序)代码:

java 复制代码
    int[] tmp;
    public int reversePairs(int[] nums) {
        int n = nums.length;
        tmp = new int[n];
        return mergeSort(nums, 0, n - 1);
    }


    public int mergeSort(int[] nums, int start, int end) {
        if (start >= end) {
            return 0;
        }
        int ret = 0;
        int mid = (start + end) / 2;
        // 先计算左面
        ret += mergeSort(nums, start, mid);
        // 再计算右面
        ret += mergeSort(nums, mid + 1, end);
        // 最后计算一左一右
        int left1 = start;
        int left2 = mid + 1;
        while (left1 <= mid && left2 <= end) {
            if (nums[left1] / 2.0 >  nums[left2]) {
                ret += mid - left1 + 1;
                left2++;
            }else {
                left1++;
            }
        }
        // 放入tmp中排序
        left1 = start;
        left2 = mid + 1;
        int i = 0;
        while (left1 <= mid && left2 <= end) {
            tmp[i++] = nums[left1] <= nums[left2] ? nums[left1++] : nums[left2++];
        }
        while (left1 <= mid) {
            tmp[i++] = nums[left1++];
        }
        while (left2 <= end) {
            tmp[i++] = nums[left2++];
        }
        // 合并数组
        for (int j = start; j <= end; j++) {
            nums[j] = tmp[j - start];
        }
        return ret;
    }
相关推荐
AI进化营-智能译站1 分钟前
ROS2 C++开发系列13-运算符重载让ROS2消息处理更自然
java·开发语言·c++·ai
AI科技星2 分钟前
《全域数学》第一部 数术本源 第三卷 代数原本第14篇 附录二 猜想证明【乖乖数学】
人工智能·算法·数学建模·数据挖掘·量子计算
shjita12 分钟前
java根据键值对中值的大小进行排序的手法。
java·开发语言·servlet
Wect16 分钟前
LeetCode 72. 编辑距离:动态规划经典题解
前端·算法·typescript
憨波个24 分钟前
【说话人日志】DOVER-Lap:overlap-aware diarization 输出融合算法
人工智能·深度学习·算法·音频·语音识别
叼烟扛炮31 分钟前
C++第四讲:类和对象(下)
c++·算法·类和对象
Rabitebla31 分钟前
vector 的骨架:三根指针、模板陷阱与迭代器失效的第一现场
开发语言·数据结构·c++·算法
薪火铺子32 分钟前
Spring Security 6.x 实战指南
java·后端·spring
善恶怪客44 分钟前
Java-数据类型
java
代码不停1 小时前
BFS解决floodfill算法题目练习
算法·宽度优先