当前位置: 首页 > article >正文

归并排序练习

归并排序使用先处理左边,再处理右边的思想。

排序数组

912. 排序数组 - 力扣(LeetCode)

思路

先算出数组中的中间值,再对左边递归,再对右边递归即可对左右两区间各自进行排序。

mergeSort(nums, left, mid);

mergeSort(nums, mid + 1, right);

合并两数组 

定义cur1起始点为左边数组的第一位,定义cur2起始点为右边数组的第一位,如图:

再将两数较小的填入临时数组。

while(cur1 <= mid && cur2 <= right)

tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];

 由于条件是与(&&)所以可能存在只满足其中一个条件的情况,所以我们需要处理没有遍历完的数组。

while(cur1 <= mid) tmp[i++] = nums[cur1++];

while(cur2 <= right) tmp[i++] = nums[cur2++];

最后再输出数组即可

代码

class Solution 
{
    vector<int> tmp;
public:
    vector<int> sortArray(vector<int>& nums)
    {
        tmp.resize(nums.size());
        mergeSort(nums, 0, nums.size() - 1);
        return nums;
    }

    void mergeSort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;

        int mid = (left + right) >> 1;
        //对左右区间排序
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);

        //合并两数组      
        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right)
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];

        //处理没有遍历完的数组
        while (cur1 <= mid) tmp[i++] = nums[cur1++];
        while (cur2 <= right) tmp[i++] = nums[cur2++];

        for (int i = left; i <= right; i++)
            nums[i] = tmp[i - left];
    }
};

交易逆序对的总数

LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

思路

本题依然使用归并思想,与上题的区别是合并数组步骤:若cur1所指向的值小于等于cur2指向值,则正常将数组按顺序合并,若cur1所指向的值大于cur2指向值,则cur1到mid中间的值都大于cur1,所以这些值都可以与cur2前的值形成逆序对,如此可以推断出逆序对数为mid - cur1 + 1,如图所示

再对未排完的剩余值进行排序即可。

代码 

class Solution {
    int tmp[50010];
public:
    int reversePairs(vector<int>& record)
    {
        return mergeSort(record, 0, record.size() - 1);
    }

    int mergeSort(vector<int>& record, int left, int right)
    {
        if (left >= right) return 0;

        int ret = 0, mid = (left + right) >> 1;
        ret += mergeSort(record, left, mid);
        ret += mergeSort(record, mid + 1, right);

        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right)
        {
            if (record[cur1] <= record[cur2]) tmp[i++] = record[cur1++];
            else
            {
                ret += mid - cur1 + 1;
                tmp[i++] = record[cur2++];
            }
        }

        //排序
        while (cur1 <= mid) tmp[i++] = record[cur1++];
        while (cur2 <= right) tmp[i++] = record[cur2++];
        for (int j = left; j <= right; j++)
            record[j] = tmp[j - left];
        return ret;
    }
};

 计算右侧小于当期元素的个数

315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)

思路 

本题需要记录临时下标与原始下标,因为我们需要计算比某一值小的所有值,在合并数组期间会导致下标发生混乱。tmpIndex存储数组的临时下标。tmpNum用于临时存储元素值。后面每对数组进行处理都要注意临时下标和原始下标的操作。

代码

class Solution
{
    int tmpNums[100010];
    vector<int> index;//记录原始下标
    vector<int> ret;
    int tmpIndex[100010];
public:
    vector<int> countSmaller(vector<int>& nums)
    {
        int n = nums.size();
        ret.resize(n);
        index.resize(n);

        for (int i = 0; i < n; i++)
            index[i] = i;

        mergeSort(nums, 0, n - 1);
        return ret;
    }

    void mergeSort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;
        int mid = (left + right) >> 1;

        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);

        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right)
        {
            if (nums[cur1] <= nums[cur2])
            {
                tmpNums[i] = nums[cur2];
                tmpIndex[i++] = index[cur2++];
            }
            else
            {
                ret[index[cur1]] += right - cur2 + 1;//重点
                tmpNums[i] = nums[cur1];
                tmpIndex[i++] = index[cur1++];
            }
        }
        while (cur1 <= mid)
        {
            tmpNums[i] = nums[cur1];
            tmpIndex[i++] = index[cur1++];
        }
        while (cur2 <= right)
        {
            tmpNums[i] = nums[cur2];
            tmpIndex[i++] = index[cur2++];
        }
        for (int j = left; j <= right; j++)
        {
            nums[j] = tmpNums[j - left];
            index[j] = tmpIndex[j - left];
        }
    }
};

翻转对

493. 翻转对 - 力扣(LeetCode)

思路

这题与逆序对的区别只有在递归后添加判断条件

while (cur1 <= mid)
{
    while (cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;
    if (cur2 > right) break;
    ret += right - cur2 + 1;
    cur1++;
}        

只有cur1指向值大于cur2指向值两倍时才让cur2向后移。

代码 

class Solution
{
    int tmp[50010];
public:
    int reversePairs(vector<int>& nums)
    {
        return mergeSort(nums, 0, nums.size() - 1);
    }

    int mergeSort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return 0;
        int ret = 0, mid = (left + right) >> 1;

        ret += mergeSort(nums, left, mid);
        ret += mergeSort(nums, mid + 1, right);

        int cur1 = left, cur2 = mid + 1, i = left;
        while (cur1 <= mid)
        {
            while (cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;
            if (cur2 > right) break;
            ret += right - cur2 + 1;
            cur1++;
        }

        //合并
        cur1 = left, cur2 = mid + 1;
        while (cur1 <= mid && cur2 <= right)
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur2++] : nums[cur1++];
        while (cur1 <= mid) tmp[i++] = nums[cur1++];
        while (cur2 <= right) tmp[i++] = nums[cur2++];

        for (int j = left; j <= right; j++)
            nums[j] = tmp[j];
        return ret;
    }
};


http://www.kler.cn/a/526241.html

相关文章:

  • 01-时间与管理
  • 解析“in the wild”——编程和生活中的俚语妙用
  • (笔记+作业)书生大模型实战营春节卷王班---L0G2000 Python 基础知识
  • Visual Studio使用GitHub Copilot提高.NET开发工作效率
  • postgresql的用户、数据库和表
  • 【PowerQuery专栏】PowerQuery实现数据库访问系列函数
  • 深入解析 JPA 实体生命周期回调
  • (0基础版,无需输入代码爬取)新手小白初步学习八爪鱼采集器
  • 图论——spfa判负环
  • 【ArcGIS微课1000例】0141:提取多波段影像中的单个波段
  • Hive:窗口函数[ntile, first_value,row_number() ,rank(),dens_rank()]和自定义函数
  • linux的/proc 和 /sys目录差异
  • [NVME] PMRCAP-Persistent Memory Region Capabilities
  • 10.4 字符编码和解码
  • 一文大白话讲清楚webpack进阶——8——Module Federation
  • 学习:ASCII码是计算机中用得最广泛的字符集及其编码
  • 算法总结-哈希表
  • Ansys Maxwell:采用对称性的双转子轴向磁通电机
  • 【AI论文】BIOMEDICA:一个源自科学文献的开放生物医学图像-标注档案、数据集及视觉-语言模型
  • 从零开始学习安时积分法(STM32实现程序)
  • Databricks:统一的数据和 AI 平台
  • docker安装nacos2.2.4详解(含:nacos容器启动参数、环境变量、常见问题整理)
  • [C]基础9.深入理解指针(1)
  • 接口使用实例(1)
  • SAP SD学习笔记27 - 贩卖契约(框架协议)3 - 基本契约 - 定期请求(开票计划)
  • pandas基础学习:常用基本函数