归并排序的应用

归并排序的特点是左右两个已经排好序的子数组进行合并成更大的数组的一个过程

复制代码
    void Merge(int left, int right) {
        int mid = (left + right) / 2;
        int i = left;
        int j = mid;
        int index = left;
        while (i < mid && j < right) {
            if (m_data[i] <= m_data[j]) {
                m_midData[index] = m_data[i];
                ++i;
            }
            else {
                m_midData[index] = m_data[j];
                ++j;
            }
            ++index;
        }

        while (i < mid) {
            m_midData[index] = m_data[i];
            ++i;
            ++index;
        }

        while (j < right) {
            m_midData[index] = m_data[j];
            ++j;
            ++index;
        }

        while (left < right) {
            m_data[left] = m_midData[left];
            ++left;
        }
    }

    void MergeSort(int left, int right) {
        if (left + 1 >= right)
            return;

        int mid = (left + right) / 2;
        MergeSort(left, mid);
        MergeSort(mid, right);
        Merge(left, right);
    }
复制代码

如上所示,进行递归排序;

 

递归排序的应用:

1、https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/

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

假设当前已经排好序的两个数组,计算右侧数组中分别小于左侧数组中的每个元素个数则可以在O(n)的时间内计算出来

可行性:1、当前只有两个元素,统计右侧小于左侧的元素;2、当前有4个元素左右两边各两个,则由于第一点已经统计了各自内部的小于左侧的个数,则内部无需再进行统计,只需统计右边两个元素分别小于左边两个元素的个数;同理可以推到多个多个元素的合并

复制代码
class Solution {
    void Merge(int left, int right) {
        int mid = (left + right) / 2;
        int i = left;
        int j = mid;
        int index = left;
        while (i < mid && j < right) {
            if (m_data[i] <= m_data[j]) {
                m_midIndex[index] = m_index[i];
                m_midData[index] = m_data[i];
                m_ret[m_index[i]] += j - mid;
                ++i;
            } else {
                m_midIndex[index] = m_index[j];
                m_midData[index] = m_data[j];
                ++j;
            }
            ++index;
        }

        while (i < mid) {
            m_midIndex[index] = m_index[i];
            m_midData[index] = m_data[i];
            m_ret[m_index[i]] += right - mid;
            ++i;
            ++index;
        }

        while (j < right) {
            m_midIndex[index] = m_index[j];
            m_midData[index] = m_data[j];
            ++j;
            ++index;
        }

        while (left < right) {
            m_index[left] = m_midIndex[left];
            m_data[left] = m_midData[left];
            ++left;
        }
    }

    void MergeSort(int left, int right) {
        if (left + 1 >= right)
            return;

        int mid = (left + right) / 2;
        MergeSort(left, mid);
        MergeSort(mid, right);
        Merge(left, right);
    }
public:
    vector<int> countSmaller(vector<int>& nums) {
        m_midIndex = vector<int>(nums.size());
        m_midData = vector<int>(nums.size());
        m_ret = vector<int>(nums.size(), 0);
        m_index = vector<int>(nums.size());
        for (int i = 0; i < nums.size(); ++i)
            m_index[i] = i;
        m_data = nums;

        MergeSort(0, nums.size());

        return m_ret;
    }

    vector<int> m_index;
    vector<int> m_data;
    vector<int> m_ret;
    vector<int> m_midData;
    vector<int> m_midIndex;
};
View Code
复制代码

 

 

2、https://leetcode-cn.com/problems/count-of-range-sum/

区间和的个数;

由于计算区间和,正常需要先进行预处理:计算前缀和;sums

则问题可转化为从i+1~j的区间和为:sums[j]-sum[i]的差值是否在对应的区间

同理:对sums进行从小到大排序。。。。。。。。

 

 

总结:

统计某个元素右侧相对当前元素的关系的个数,均可转化为归并排序的过程

 

区间数量统计的另外两个算法:线段树和树状数组;如上两个也可转化为线段树或者树状数组的统计

 

posted @   LCAC  阅读(91)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示