【算法基础】1.2 归并排序

news/2024/5/17 17:26:56 标签: 算法, 排序算法, leetcode, 归并排序

文章目录


本文主要讲解归并排序及其思路的相关应用。

归并排序

题目描述

给定你一个长度为 n 的整数数列。

请你使用归并排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

912. 排序数组 https://leetcode.cn/problems/sort-an-array/

数据范围
1≤n≤100000
在这里插入图片描述

解法

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

    public void mergeSort(int[] nums, int l, int r) {
        if (l >= r) return;
        int mid = l + r >> 1;
        mergeSort(nums, l, mid);
        mergeSort(nums, mid + 1, r);

        int[] tmp = new int[r - l + 1];
        int i = l, j = mid + 1, k = 0;
        while (i <= mid && j <= r) {
            if (nums[i] <= nums[j]) tmp[k++] = nums[i++];  // 归并排序是稳定的
            else tmp[k++] = nums[j++];
        }
        while (i <= mid) tmp[k++] = nums[i++];
        while (j <= mid) tmp[k++] = nums[j++];

        for (i = 0; i < k; ++i) nums[l + i] = tmp[i];
    }
}

讲解

mergeSort 和 快排不同的是,先递归排序,然后进行后续的操作。(即先分开,再归并,合二为一)

e.g.
在这里插入图片描述
由于左边和右边的子数组都排好了,所以递归排序之后的操作相当于是合并两个排序好的数组,这里使用双指针算法即可。使用两个指针从头遍历两个数组,哪个小取哪个放入结果。

逆序对的数量(归并排序的思路)

剑指 Offer 51. 数组中的逆序对 https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/

题目描述

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

数据范围
1 ≤ n ≤ 100000,
数列中的元素的取值范围 [1,109]。

在这里插入图片描述

解法

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

    public int mergeSort(int[] nums, int l, int r) {
        if (l >= r) return 0;
        int mid = l + r >> 1;
        int res = mergeSort(nums, l, mid) + mergeSort(nums, mid + 1, r);
        int[] tmp = new int[r - l + 1];
        int i = l, j = mid + 1, k = 0;
        while (i <= mid && j <= r) {
            if (nums[i] <= nums[j]) tmp[k++] = nums[i++];
            else {
                tmp[k++] = nums[j++];
                res += mid - i + 1;
            }
        }
        while (i <= mid) tmp[k++] = nums[i++];
        while (j <= r) tmp[k++] = nums[j++];
        for (i = 0; i < k; ++i) nums[l + i] = tmp[i];
        return res;
    }
}

可以看出和归并排序的代码几乎一模一样。

讲解

归并排序中,我们讲到,在递归排序后的操作实际上就是将两个排序好的数组进行排序的过程。那么,当前一个数组中的数字 i 大于后一个数组中的数字 j 时,说明前一个数组中该数字 i 以及之后的数字都会比第二个数组中的数字 j 大,一共可以组成 mid - i + 1个逆序对。


时间复杂度是O(NlogN)
一共有logN层,每次的复杂度是N,因此一共是NlogN。
在这里插入图片描述


http://www.niftyadmin.cn/n/744.html

相关文章

【数据结构初阶】二、顺序表的实现

目录 一、线性表 二、顺序表 2.1 顺序表概念及结构 2.2 顺序表接口实现 2.2.1 顺序表初始化 2.2.2 顺序表的销毁 2.2.3 顺序表的打印 2.2.4 顺序表增加数据&#xff08;插入&#xff0c;头插、尾插&#xff09; 2.2.5 顺序表删除数据&#xff08;删除&#xff0c;头删…

使用HFS+cpolar组合 低成本搭建NAS(1)

云存储作为一个新概念&#xff0c;在前些年炒的火热&#xff0c;虽然伴随一系列黑天鹅事件&#xff0c;让热度快速下降&#xff0c;但云存储带来的方便深入人心。因此在大厂的云存储产品热度下降后&#xff0c;私人的NAS热度快速上升&#xff0c;其中最具代表性的&#xff0c;必…

【每日一题】分割数组

分割数组两次遍历一次遍历&#xff08;优化空间复杂度&#xff09;题目链接 题目描述&#xff1a; 给定一个数组 nums &#xff0c;将其划分为两个连续子数组 left 和 right&#xff0c; 使得&#xff1a; left 中的每个元素都小于或等于 right 中的每个元素。 left 和 right …

神经网络每次结果不一样,神经网络预测问题

1、求助&#xff1a;神经网络两次训练的结果不一样 神经网络两次训练的结果不一样&#xff0c;这是因为每次训练的迭代初值不相同&#xff08;是随机的&#xff09;&#xff0c;所以得到的结果是有差异的。一般的话&#xff0c;软件开启第一次时&#xff0c;运行得到结果是比较…

并发编程之线程池

线程池 为什么需要线程池&#xff1f; 如果性能允许的话&#xff0c;我们可以在 for 循环代码起很多的线程去帮我们执行任务&#xff0c;代码如下 public class ManyThread {public static void main(String[] args) {for (int i 0; i < 100; i) {Thread thread new Th…

pdf、markdown、docx文件预览

记录一下实现 .md \ .pdf \ .docx文件的预览。 markdown 文件预览 安装 markdown-it $> npm install --save markdown-it解析.md文件转换为 html&#xff0c;然后添加到 dom 节点中。 import MarkdownIt from "markdown-it";function parseFile(fileUrl) {// …

【Linux】yum 与 vim 的基本使用

文章目录一、yum 背景知识1、商业生态2、开源生态3、软件生态本土化二、yum 的基本使用1、查看软件包2、安装软件3、卸载软件三、vim 的基本使用1、vim 的基本概念2、vim 的基本操作2.1 模式间切换2.2 光标定位2.3 文本复制2.4 文本编辑2.5 底行模式的操作四、简单 vim 配置2、…

1024_回首2022我做了啥

2022年的总结技能的变迁工作变化生活变化环境变化结尾技能的变迁 vue2框架使用、sql、js编写-> vue3框架使用&#xff0c;antdesign的ui框架使用 自学了微信小程序&#xff0c;优化了个人博客&#xff0c;自学webpack打包优化。 博客&#xff1a;https://yongma16.xyz/#/ 博…