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

文章目录

  • [一. 力扣 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;
    }
相关推荐
huangdong_8 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
記億揺晃着的那天8 小时前
Java 调用外部 Go 程序的实践:ProcessBuilder 在生产环境中的应用
java·golang·processbuilder
JAVA面经实录9178 小时前
Java 数据结构与算法 (终极完整学习文档)
java·数据结构·算法
JAVA面经实录9179 小时前
操作系统面试题
java·服务器·数据库·计算机网络·面试
一杯奶茶¥10 小时前
基于springboot的失物招领管理系统带万字文档 校园失物招领管理系统 失物认领管理系统java springboot vue
java·vue.js·spring boot·java项目
不能只会打代码10 小时前
边缘视频分析平台的架构设计与性能优化——从750ms到190ms的调优之路
java·spring boot·redis·性能优化·边缘计算·物联网竞赛
小刘|10 小时前
Spring AI Alibaba 集成和风天气 API 实战
java·服务器·前端
KANGBboy10 小时前
java知识五(继承)
java·开发语言
AI人工智能+电脑小能手10 小时前
【大白话说Java面试题 第117题】【并发篇】第17题:线程有几种状态,之间如何转换?
java·开发语言·面试
DIY源码阁10 小时前
JavaSwing饮品管理系统 - MySQL版
java·数据库·mysql·eclipse