第m小的数

  • 问题
  • 分析
  • 代码

问题

给定一个无重复元素的无序数组,求其第m小的元素。

如:{1,5,3,6,2,8,5} 求其第3小的元素

答案:3


分析

  1. 直观可以考虑通过对数组进行排序求解,而基于排序算法的时间复杂度下界为 O ( n l o g n ) O(nlogn) O(nlogn),即通过排序算法求解的时间复杂度不会低于 O ( n l o g n ) O(nlogn) O(nlogn)。
  2. 借助快速排序思想,每次遍历作为主元素的所在的分割位置确定后固定,当前子数组排序完成后,设主元素的索引为 n n n,则 n n n即为该数组中第 n + 1 n+1 n+1小的元素,故此,求数组中第 m m m小的元素,只需在排序中的某一轮中确定下标为 m − 1 m-1 m−1处位置的主元素即可。
  3. 不同于快速排序的过程,寻找第m小的元素目的在于单个元素的查询,不在意所有元素的排序,故此,当轮排序完成后
    1. 若主元素索引小于 m − 1 m-1 m−1,则表示所查询元素位于主元素的右侧,只需对右侧子数组再进行数组划分,左侧子数组不在关注。
    2. 若主元素索引大于 m − 1 m-1 m−1,则表示所查询元素位于主元素的左侧,只需对左侧子数组再进行数组划分,右侧子数组不再关注。
    3. 若主元素等于 m − 1 m-1 m−1,则表示当前主元素即为所查询元素,查询结束。
  4. 该算法能够实现主要借助于快速排序中,当每一轮的排序完成,主元素位置确定后,其索引将不会在之后的子数组排序中被改变,即每一轮确定的主元素的位置与其在整体排序完成后数组中的位置保持一致的特点。
  5. 该算法的时间复杂度 T ( n ) T(n) T(n)满足: O ( n ) ≤ T ( n ) ≤ O ( n 2 ) O(n) \le T(n) \le O(n^2) O(n)≤T(n)≤O(n2)
  6. 该算法的空间复杂度为 O ( n ) O(n) O(n),若不保证原数组的次序,则空间复杂度为 O ( 1 ) O(1) O(1).

代码

  1. c++

    #include <exception>
    #include <vector>
    #include <ctime>
    using std::vector;
    using std::exception;
    using std::rand;class MMin {private:vector<int>* parr = nullptr; // 重新分配被查询数组,避免改变原数组,成员替代递归传参int m;int mmin; // 存放查询到的结果
    public:int m_min(const vector<int>& arr, int m) { // 对外接口if (arr.size() == 0)throw exception("arr cannot be empty!");if (m < 1 || m > arr.size())throw exception("m cannot be out of range!");this->parr = new vector<int>(arr); // 复制数组用于操作this->m = m;this->_m_min(0, this->parr->size());delete this->parr; // 释放临时数组this->parr = nullptr;return this->mmin;}
    private:void _m_min(int left, int right) { // 内部递归实现// 一个元素时终止递归if (left + 1 == right) {// 一个元素时直接判断该元素索引是否符合条件if (this->m - 1 == left)this->mmin = this->parr->at(left);return;}// 随机选取主元素,交换至尾元素std::srand(std::time(nullptr));int pos = rand() % (right - left) + left;int main_element = this->parr->at(pos);(*this->parr)[pos] = (*this->parr)[right - 1];(*this->parr)[right - 1] = main_element;// 数组划分,遍历除主元素外的其余元素int i = left - 1, j = left, temp = 0;for (; j < right - 1; j++) {if (this->parr->at(j) < main_element) {temp = (*this->parr)[i + 1];(*this->parr)[i + 1] = (*this->parr)[j];(*this->parr)[j] = temp;i++;}}// 交换主元素至中间,完成数组划分temp = main_element;(*this->parr)[right - 1] = (*this->parr)[i + 1];(*this->parr)[i + 1] = temp;i++; // i指向主元素// 当主元素索引恰好满足条件,查询结束if (this->m - 1 == i)this->mmin = this->parr->at(i);// 当主元素索引大于m-1,则对左侧子数组进行排序查询else if (this->m - 1 < i)this->_m_min(left, i);// 当主元素索引小于m-1,则对右侧子数组进行排序查询elsethis->_m_min(i + 1, right);}
    };
    
  2. java

    import java.lang.RuntimeException;
    import java.util.Random;public class MMin {// 存放被查询数组的拷贝,避免改变原数组,成员替代递归传参private int[] arr = null; private int m;private int mmin; // 存放查询到的结果public int m_min(final int[] arr, int m) { // 对外接口if (arr.length == 0)throw new RuntimeException("arr cannot be empty!");if (m < 1 || m > arr.length)throw new RuntimeException("m cannot be out of range!");this.arr = new int[arr.length]; // 复制数组用于操作for (int i = 0; i < arr.length; i++)this.arr[i] = arr[i];this.m = m;this._m_min(0, this.arr.length);this.arr = null; // 拷贝数组置空return this.mmin;}private void _m_min(int left, int right) { // 内部递归实现// 一个元素时终止递归if (left + 1 == right) {// 一个元素时直接判断该元素索引是否符合条件if (this.m - 1 == left)this.mmin = this.arr[left];return;}// 随机选取主元素,交换至尾元素Random rdm = new Random();int pos = rdm.nextInt(right - left) + left;int main_element = this.arr[pos];this.arr[pos] = this.arr[right - 1];this.arr[right - 1] = main_element;// 数组划分,遍历除主元素外的其余元素int i = left - 1, j = left, temp = 0;for (; j < right - 1; j++) {if (this.arr[j] < main_element) {temp = this.arr[i + 1];this.arr[i + 1] = this.arr[j];this.arr[j] = temp;i++;}}// 交换主元素至中间,完成数组划分temp = main_element;this.arr[right - 1] = this.arr[i + 1];this.arr[i + 1] = temp;i++; // i指向主元素// 当主元素索引恰好满足条件,查询结束if (this.m - 1 == i)this.mmin = this.arr[i];// 当主元素索引大于m-1,则对左侧子数组进行排序查询else if (this.m - 1 < i)this._m_min(left, i);// 当主元素索引小于m-1,则对右侧子数组进行排序查询elsethis._m_min(i + 1, right);}
    };
    
  3. python

    from random import randintclass MMin:def __init__(self):self.__arr = [] # 存放查找数组的拷贝,排序将不改变原数组self.__mmin = None  # 存放第m小的元素self.__m = None # 存放m,减少递归传参def m_min(self, arr: list, m: int) -> int:if len(arr) == 0: # 数组判空raise Exception("arr cannot be empty.")if m < 1 or m > len(arr): # 判断m是否有效raise Exception("m cannot be out of range.")self.__arr = arr[:]self.__m = mself.__m_min(0, len(arr))self.__arr.clear()return self.__mmindef __m_min(self, left: int, right: int) -> None:# 一个元素时递归终止if left + 1 == right:# 当仅剩一个元素时直接判断该元素索引是否满足条件if self.__m - 1 == left:self.__mmin = self.__arr[left]return None# 随机选取主元素,交换至尾元素pos = randint(left, right-1)main_element = self.__arr[pos]self.__arr[pos] = self.__arr[right - 1]self.__arr[right - 1] = main_element# 遍历除主元素外的其余元素,数组划分i = left - 1j = leftwhile j < right - 1:if self.__arr[j] < main_element:temp = self.__arr[j]self.__arr[j] = self.__arr[i+1]self.__arr[i+1] = tempi += 1j += 1# 交换尾部主元素至中间作为分割,完成数组划分temp = main_elementself.__arr[right-1] = self.__arr[i+1]self.__arr[i+1] = tempi += 1 # 使i指向主元素# 当主元素索引正好满足条件时,直接返回if self.__m - 1 == i:self.__mmin = main_element# 当主元素索引大于m-1时,排序查找左侧子数组elif self.__m - 1 < i:self.__m_min(left, i)# 当主元素索引小于m-1时,排序查找右侧子数组else :self.__m_min(i+1,right)
    

分而治之策略-第m小的数(c++、java、python)相关推荐

  1. python递归算法 电影院票价问题_算法课堂实验报告(二)——python递归和分治(第k小的数,大数乘法问题)...

    python实现递归和分治 一.开发环境 开发工具:jupyter notebook 并使用vscode,cmd命令行工具协助编程测试算法,并使用codeblocks辅助编写C++程序 编程语言:py ...

  2. 小明特别喜欢打扑克牌,除了喜欢斗地主和德州扑克之外,还喜欢一种叫桥牌的游戏,桥牌的具体规则相当复杂,有叫牌、打牌和计分三个阶段,还有不断变化的局况,局况可能影响叫牌打牌策略。但是小明暂时不关心这一些,

    题目描述: 小明特别喜欢打扑克牌,除了喜欢斗地主和德州扑克之外,还喜欢一种叫桥牌的游戏,桥牌的具体规则相当复杂,有叫牌.打牌和计分三个阶段,还有不断变化的局况,局况可能影响叫牌打牌策略.但是小明暂时不 ...

  3. 中国电子学会青少年编程能力等级测试图形化四级编程题:小猴数草莓

    「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复[Scratch]或[Python],即可进入.如果加入了之前的社群不需要重复加入. 我们将有关编程题目的教学视频已经发布到抖 ...

  4. 算法导论9.2-3习题解答(寻找第i小的数)

    CLRS 9.2-3 : 写出RANDOMIZED-SELECT的一个迭代版本 在这里,顺便实现在数组内寻找第i小的数值. #include <iostream> #include < ...

  5. 在数组中找到第 k 小的数

    在数组中找到第 k 小的数 [要求] 如果 arr 长度为 N,要求时间复杂度为 O(N),额外空间复杂度为 O(1). public static int[] getMinKNumByHeap(in ...

  6. “策小编数洞”开工啦,欢迎来唠两块钱儿的

    愁, 数据, 金字塔, 超多指标, 留存率下降, 行为事件分析, 领导让我出报表, 搭建数据分析平台, 不会数据分析怎么办! 让飞天小女警策小编来拯救你,你只需要一个数(树)洞,春天把问题丢进去,秋天 ...

  7. html5数组查找第二大数,2021-06-29:在两个都有序的数组中找整体第K小的数。

    2021-06-29:在两个都有序的数组中找整体第K小的数. 福大大 答案2021-06-29: 1.A和B长度不等的时候,需要把A和B的长度变成相等. A是短数组,B是长数组. 第k小的数,k从1开 ...

  8. 十位数和个位数交换python_Python实现100以内十位数数字比个位数数字小的数

    原标题:Python实现100以内十位数数字比个位数数字小的数 最近在学习Python和C#,这2种语言都是支持面向对象的,想借此来更加深入地学习.了解面向对象. # -*- coding:utf-8 ...

  9. 面试题:找两个有序数组所有数第K小的数

    给定两个有序数组arr1和arr2,再给定一个整数k,返回两个数组中所有数中第k小的数.要求:如果arr1的长度为N,arr2的长度为M,时间复杂度请达到O(log(min{M, N}) ) 例如: ...

最新文章

  1. oracle的rman备份保留天数,RMAN 基于时间的备份保留策略调整
  2. while(getchar()=='\n')continue;为什么作用是清空行
  3. MATLAB作图方法与技巧(二)
  4. Apache CXF 3.0:CDI 1.1支持可替代Spring
  5. Java EE中的配置管理
  6. spring 上下文_一次性教你彻底理解 Spring容器和应用上下文!
  7. 鼠标屏幕取词技术的原理和实现 (转)
  8. 海森(hessian)矩阵
  9. matlab中的连乘符号,数学中的连乘符号
  10. Ubuntu安装Onedrive
  11. 网络打不其他计算机的共享文件,快速解决“电脑无法访问共享文件夹”的4种方法!...
  12. java 导出word 带图片
  13. 生成arp报文的verilog实现
  14. js经纬度打开腾讯地图
  15. python - 例题分析:工时与工资
  16. 玩转iOS开发:集成 Union Pay - 银联支付
  17. Anchor-free的目标检测文章
  18. android pick file,Materia风格的Android文件选择器:MaterialFilePicker_Android_移动开发
  19. python实时读取日志_paramiko使用tail实时获取服务器的日志输出详解
  20. 数码相机名词解释-变焦镜头 物距 枕形失真 视角 透视 微距摄影 焦距系数

热门文章

  1. 初探Spark-使用大数据分析2000W行数据
  2. centos 7 安装FastDFS 5.09
  3. FFT原理(基2DIT-FFT)及C语言编程思路及实现
  4. 2020年浙江大学软件学院预推免面经
  5. Python 实现windwos以及ubuntu avi转换mp4
  6. android ios打包工具下载,IOS移动开发之快速打包工具---- iTunes 降级 到12.6,回到你熟悉的版本...
  7. 解决ITunes安装显示该电脑已经安装更新的版本
  8. 网络电视连接服务器显示1404,电信网络电视连接错误代码为1404为什么
  9. 视频转音频mp3软件哪个好?这些转换软件就很好用
  10. chopper云音乐开发笔记