《算法题讲解指南:优选算法-分治-快排》--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++算法代码:

cpp 复制代码
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++算法代码:

cpp 复制代码
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个数 同样采用三区划分策略,通过计算各区元素数量直接定位目标区间,相比排序和堆方法更高效。**希望大家能有所收获!

相关推荐
SCBAiotAigc2 小时前
2026.3.7:具身智能之51单片机<二>:ISP烧录过程
c++·人工智能·单片机·嵌入式硬件·51单片机·c
Galerkin码农选手2 小时前
per_tenor_quant_fp8和per_token_quant_fp8算法解读
人工智能·pytorch·算法
tankeven2 小时前
HJ125 最大最小路
c++·算法
MegaDataFlowers2 小时前
认识复杂度和简单排序算法
java·算法·排序算法
MSTcheng.2 小时前
【算法】前缀和:『560. 和为 K 的子数组 & 1314.矩阵区域和』
线性代数·算法·矩阵
梦游钓鱼2 小时前
Timestamp.cc和Timestamp.h文件分析
开发语言·c++
luckycoding2 小时前
739. 每日温度
算法·leetcode·职场和发展
一只黑鸟2 小时前
基于STM32的罐装水泥成分实时检测系统设计与实现(含有matlab仿真)
stm32·嵌入式硬件·算法·matlab·毕设
十年编程老舅2 小时前
Linux GDB 调试超详细教程:入门 + 实战
linux·c++·gdb