快速排序——寻找数组第K大数(由浅入深,四种方法对比讲解!)

寻找数组第K大数是大厂面试中经常考到的一题,有的小机灵鬼直接用sort()进行排序,两行代码解决,这样看似可行,实则掉入了出题人的陷阱。面试官希望看到的是你对算法的理解,而不是函数的调用。下面,我就以本题为例,由浅入深,用四种方法来分别解决此题,最后推荐的是快速排序,这里先给出快速排序的动态演示图,具体讲到思路以及实现详见文中!
在这里插入图片描述


题目:寻找第K大

在这里插入图片描述


方法一:全局排序

使用C++中内置函数sort进行全局排序,再取第K大值:

class Solution {
public:
    int findKth(vector<int> a, int n, int K) {
        sort(a.begin(), a.end());
        return a[n-K];
    }
};

提交结果:
在这里插入图片描述


方法二:局部排序

使用冒泡排序的思想,每次将最大的值放在数组尾部,直到第K个,时间复杂度O(nk):

class Solution {
public:
    int findKth(vector<int> a, int n, int K) {
        for(int i=0; i<K; ++i)
        {
            for(int j=0; j<n-i-1; ++j)
            {
                if(a[j]>a[j+1])
                {
                    int temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
                }
            }
        }
        return a[n-K];
    }
};

提交结果:
在这里插入图片描述


方法三:优先队列

最小堆的方式实现,有关堆与优先队列的关系,可参考:堆和优先队列

class Solution {
public:
    int findKth(vector<int> a, int n, int K) {
        priority_queue <int, deque<int>, greater<int>> nums; //队首最小,从小到大排序
        for(int i=0; i<n; ++i)
        {
            if(i<K)
            {
                nums.push(a[i]);
            }
            else
            {
                if(a[i]>nums.top())
                {
                    nums.pop();
                    nums.push(a[i]);
                }
            }
        }
        return nums.top();
    }
};

提交结果:
在这里插入图片描述


方法四:快速排序

快排思想:通过一趟排序将待排序元素分成独立的两部分,其中一部分记录的元素均比另一部分记录的元素要小,则可分别对这两部分记录继续进行排序,直到整个序列有序为止。具体做法如下:

  1. 首先选取基准元素base(首元素,中间元素,最后元素,随机元素等等)。
  2. 以基准元素为基准,将小于基准元素的元素放在前面,大于基准元素的放在后面。
  3. 然后以基准元素为界限,分为两组数据。
  4. 两组元素重复1、2和3步骤,直至比较排序完成。

快排的最坏运行时间为O(n^2),平均运行时间为O(nlogn)。由于跳跃式交换比较,故不稳定!动态演示过程如下:

在这里插入图片描述

快速排序的C++实现方法如下:

vector<int> quickSort(vector<int>&nums, int start, int end)
{
	if (start >= end) return nums;
	int base = nums[start];
	int i = start;
	int j = end;
	while (i < j)
	{
        while (i < j && nums[j] >= base) j--; //从右往左,寻找比base小的数
        swap(nums[i], nums[j]); //找到比base小的数,即与base交换位置
        while (i < j && nums[i] <= base) i++; //从左往右,寻找比base大的数
        swap(nums[i], nums[j]); //找到比base大的数,即与base交换位置
	}
	quickSort(nums, start, i - 1);
	quickSort(nums, i + 1, end);
	return nums;
}

对于本题,可以先采用快排的方法进行全局排序,然后直接返回第K大即可:

class Solution {
public:
    vector<int> quickSort(vector<int>&nums, int start, int end)
    {
        if (start >= end) return nums;
        int base = nums[start];
        int i = start;
        int j = end;
        while (i < j)
        {
            while (i < j && nums[j] >= base) j--; //从右往左,寻找比base小的数
            swap(nums[i], nums[j]); //找到比base小的数,即与base交换位置
            while (i < j && nums[i] <= base) i++; //从左往右,寻找比base大的数
            swap(nums[i], nums[j]); //找到比base大的数,即与base交换位置
        }
        quickSort(nums, start, i - 1);
        quickSort(nums, i + 1, end);
        return nums;
    }
    
    int findKth(vector<int> a, int n, int K) {
        quickSort(a, 0, n-1);
        return a[n-K];
    }
};

显然,这不是最佳结果。我们进一步考虑,发现在快排过程中,如果在base右边的元素个数超过K个,那么结果肯定在base右边,左边的元素就可以不考虑再去排序了。因此,在迭代过程中,我们加一句判断,这样计算的时间复杂度就能进一步减小。如下所示:

class Solution {
public:
    vector<int> quickSort(vector<int>&nums, int start, int end, int K)
    {
        if (start >= end) return nums;
        int base = nums[start];
        int i = start;
        int j = end;
        while (i < j)
        {
            while (i < j && nums[j] >= base) j--; //从右往左,寻找比base小的数
            swap(nums[i], nums[j]);
            while (i < j && nums[i] <= base) i++;
            swap(nums[i], nums[j]);
        }
        if(nums.size()-i<K) //如果base右边的数超过K个,则第K大数肯定在base右边,此时就不需要对base左边的进行排序
            quickSort(nums, start, i - 1, K);
        quickSort(nums, i + 1, end, K);
        return nums;
    }
    
    int findKth(vector<int> a, int n, int K) {
        quickSort(a, 0, n-1, K);
        return a[n-K];
    }
};

最后的提交结果:
在这里插入图片描述


参考链接:

解决无人机送药路径优化问题时,遗传算法(GA)、模拟退火算法(SA)和粒子群优化算法(PSO)都是有效的工具。它们在解决优化问题,特别是NP完全问题如TSP(旅行商问题)方面有着各自的优势和特点。 参考资源链接:[无人机配送:TSP问题下的优化算法应用与分析](https://wenku.csdn.net/doc/4uju6qfggw?spm=1055.2569.3001.10343) 首先,遗传算法通过模拟自然选择的过程来优化问题。它使用种群的概念,种群中的每个个体代表一个可能的解决方案(即无人机的一条可能路径)。通过选择、交叉(杂交)和变异操作,算法迭代地改进解决方案。在无人机送药的上下文中,路径即为染色体,而路径上的每一个城市(或配送点)可以看作是一个基因。 模拟退火算法则是通过模拟物理中固体退火过程中的能量降低原理来搜索最优解。它允许在搜索过程中接受劣于当前解的解,以概率性的方法跳出局部最优陷阱。SA算法在初期以较高的概率接受劣解,随着温度逐渐降低,这种接受概率也逐渐减小,从而使得算法能够收敛到全局最优解。 粒子群算法则受到鸟群觅食行为的启发,通过模拟鸟群中每个粒子的运动来寻找最优解。每个粒子根据自身的经验和群体的经验来调整自己的运动,即解的搜索方向和步长。 在实际应用中,首先要定义一个适应度函来评价路径的优劣,通常是路径的总长度的倒。然后设置算法的参,如GA中的种群小、交叉率、变异率;SA中的初始温度和冷却率;PSO中的学习因子和惯性权重。 接下来,通过迭代运行算法,直到满足停止条件,比如达到预定的迭代次或解的质量不再有显著的提升。最后,比较三种算法的结果,主要指标包括最短路径长度、算法的收敛速度和解的稳定性。 为了更深入理解这些算法在无人机送药路径优化问题上的应用和性能比较,建议参阅《无人机配送:TSP问题下的优化算法应用与分析》。该论文详细探讨了这三种算法的理论基础和实际应用,以及它们在解决此类优化问题时的优势和局限性,提供了丰富的案例分析和结果对比。这将有助于你全面掌握不同算法的使用,并指导你针对特定问题选择最适合的优化策略。 参考资源链接:[无人机配送:TSP问题下的优化算法应用与分析](https://wenku.csdn.net/doc/4uju6qfggw?spm=1055.2569.3001.10343)
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI 菌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值