《算法题讲解指南:优选算法-分治-快排》--45.数组中的第k个最大元素,46.最小的k个数

《算法题讲解指南:优选算法-分治-快排》--45.数组中的第k个最大元素,46.最小的k个数

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》

《C++入门到进阶&自我学习过程记录》《算法题讲解指南》--优选算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

45.数组中的第k个最大元素

题目链接:

题目描述:

题目示例:

解法(快速选择算法):

算法思路:

C++算法代码:

算法总结及流程解析:

46.最小的k个数

题目链接:

题目描述:

题目示例:

​编辑

解法(快速选择算法):

算法思路:

C++算法代码:

算法总结及流程解析:

结束语


45.数组中的第k个最大元素

题目链接:

215. 数组中的第K个最大元素 - 力扣(LeetCode)

题目描述:

题目示例:

解法(快速选择算法):

算法思路:

      在快排中,当我们把数组「分成三块」之后:[ left ,l ] [ l + 1,r - 1 ] [ r,right ],我们可以通过计算每一个区间内元素的「个数」,进而推断出我们要找的元素是在「哪一个区间」里面。

      那么我们可以直接去「相应的区间」去寻找最终结果就好了。

C++算法代码:

class Solution { public: int Top_k(vector<int>& nums, int left, int right, int k) { if(left == right) { return nums[left]; } int l = left - 1, r = right + 1, i = left; //1、随机选择基准元素 int key = nums[rand() % (right - left + 1) + left]; //2、根据基准元素将数组分三块 while(i < r) { if(nums[i] > key) { swap(nums[i], nums[--r]); } else if(nums[i] < key) { swap(nums[i++], nums[++l]); } else { i++; } } //若右边区域元素个数>=k,说明第k大的数在右边区域,继续判断 if(right - r + 1 >= k) { return Top_k(nums, r, right, k); } //若右边区域个数<k,但中间加右边区域个数>=k,说明第k大的数在中间区域,则就是key else if(right - l >= k) { return key; } //若中间加右边区域个数<k,说明第k大的数在左边区域,继续判断 //对于整个数组第k大的数,在左边区域相当于是第(k-中间区域个数-右边区域个数)大的数 else { return Top_k(nums, left, l, k - (right - l)); } } int findKthLargest(vector<int>& nums, int k) { srand(time(NULL)); return Top_k(nums, 0, nums.size() - 1, k); } };

算法总结及流程解析:

46.最小的k个数

题目链接:

LCR 159. 库存管理 III - 力扣(LeetCode)

题目描述:

题目示例:

解法(快速选择算法):

算法思路:

      在快排中,当我们把数组「分成三块」之后:[ l,left ] [ left + 1,right -1 ] [ right,r ],我们可以通过计算每一个区间内元素的「个数」,进而推断出最小的k个数在哪些区间里面。
      那么我们可以直接去「相应的区间」继续划分数组即可。

C++算法代码:

class Solution { public: vector<int> inventoryManagement(vector<int>& stock, int cnt) { // //解法一:快排(优点:简单无脑;缺点:时间复杂度很大O(NlogN)) // sort(stock.begin(), stock.end()); // vector<int> ret; // for(int i = 0; i < cnt; i++) // { // ret.push_back(stock[i]); // } // return ret; // //解法二:堆排序(优点:时间复杂度比快排小:O(Nlogk);缺点:比较难想) // vector<int> ret; // if(cnt == 0) // { // return {}; // } // priority_queue<int> pq(stock.begin(), stock.begin() + cnt); // for(int i = cnt; i < stock.size(); i++) // { // if(pq.top() > stock[i]) // { // pq.pop(); // pq.push(stock[i]); // } // } // while(!pq.empty()) // { // ret.push_back(pq.top()); // pq.pop(); // } // return ret; //解法三:快速选择排序(优点:时间复杂度非常小:逼近O(N);缺点:方法很巧妙很难想到) if(cnt == 0) { return {}; } srand(time(NULL)); Top_k(stock, 0, stock.size() - 1, cnt); return vector<int>(stock.begin(), stock.begin() + cnt); } void Top_k(vector<int>& nums, int left, int right, int cnt) { if(left == right) { return; } int key = nums[rand() % (right - left + 1) + left]; int l = left - 1, r = right + 1, i = left; while(i < r) { if(nums[i] > key) { swap(nums[i], nums[--r]); } else if(nums[i] < key) { swap(nums[i++], nums[++l]); } else { i++; } } if(l - left + 1 >= cnt) { return Top_k(nums, left, l, cnt); } else if(r - left >= cnt) { return; } else { return Top_k(nums, r, right, cnt - (r - left)); } } };

算法总结及流程解析:

结束语

      到此,45.数组中的第k个最大元素,46.最小的k个数 这两道算法题就讲解完了。45.数组中的第k个最大元素 通过随机基准元素将数组划分为三区(大于、等于、小于基准),根据各区元素数量递归查找目标区间,时间复杂度接近O(N)。46.最小的k个数 同样采用三区划分策略,通过计算各区元素数量直接定位目标区间,相比排序和堆方法更高效。希望大家能有所收获!

Read more

C++:二叉搜索树

C++:二叉搜索树

Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。 我的博客:<但愿. 我的专栏:C语言、题目精讲、算法与数据结构、C++ 欢迎点赞,关注 目录   一  ⼆叉搜索树的性能分析和概念       1.1⼆叉搜索树的概念       1.2⼆叉搜索树的性能分析  二   ⼆叉搜索树增删查的实现,这里不支持修改(修改一个就可能不是二叉搜索树的结构了)       2.1⼆叉搜索树基本结构的实现                 2.1.1节点的定义(由于后面实现⼆叉搜索树要访问节点成员所以这里使用struct定义(默认是公有))                 2.1.2默认成员函数                         2.1.2.1⼆叉搜索树的基本结构                         2.1.2.2⼆叉搜索树的默认构造                         2.

By Ne0inhk
JDK的下载与安装教程(详细版,下载地址:官网+其它镜像)

JDK的下载与安装教程(详细版,下载地址:官网+其它镜像)

目录 1、JDK官网 2、基于JDK官网下载JDK版本 3、基于其它镜像的下载JDK版本  3.1 使用华为镜像 3.2 使用injdk镜像 4、JDK的安装 5、配置JDK的环境变量 6、ideal选择相应的JDK版本 6.1 新建项目(new project) 6.2 创建项目后,调整JDK版本 6.3通过Maven依赖来控制JDK的版本 1、JDK官网 官网地址:Java Downloads | Oracle 中国https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows 官网地址(jdk17版本之前的):https://www.oracle.

By Ne0inhk
【C++】迭代器失效

【C++】迭代器失效

迭代器失效 定义 迭代器失效是指在使用迭代器遍历容器(如vector、list、map等)的过程中,由于容器内部结构发生了变化,导致原来的迭代器不再有效,不能正确地指向它原本所指向的元素或者不能按照预期的方式进行遍历。 以 vector 为例说明 插入操作导致的迭代器失效 当在vector中插入元素时,如果插入操作导致了内存重新分配,那么所有指向该vector的迭代器都会失效。这是因为vector的存储是连续的内存空间,当插入元素使得当前容量不够时,vector会重新分配一块更大的内存空间,将原来的元素复制或移动到新的空间中,原来的迭代器所指向的内存地址就不再有效。 例: #include<iostream>#include<vector>intmain(){ std::vector<int> v ={1,2,3};auto it = v.begin(); v.push_back(4);// 插入元素可能导致内存重新分配/

By Ne0inhk
C++ 虚函数与纯虚函数:多态的核心实现基石

C++ 虚函数与纯虚函数:多态的核心实现基石

C++ 虚函数与纯虚函数:多态的核心实现基石 💡 学习目标:深度理解虚函数与纯虚函数的本质区别,掌握虚函数表的底层原理,能够灵活运用二者设计具备多态特性的类结构。 💡 学习重点:虚函数的声明与重写规则、纯虚函数与抽象类的使用场景、虚函数表的工作机制、虚函数的常见陷阱与解决方案。 一、虚函数的本质与定义 ✅ 结论:虚函数是 C++ 实现动态多态的核心,通过在基类成员函数前添加 virtual 关键字,允许派生类重写该函数,并在运行时根据对象的实际类型调用对应版本。 1.1 虚函数的声明语法 虚函数的声明必须在基类中进行,语法格式如下: class 基类名 {public:virtual 返回值类型 函数名(参数列表){// 函数体}}; 1.2 虚函数的核心特性 1. 运行时绑定:函数调用关系在程序运行时确定,而非编译时。 2. 重写规则:派生类重写的函数必须与基类虚函数的函数名、参数列表、返回值类型完全一致(协变类型除外)。 3.

By Ne0inhk