寻找最小的第k个数,寻找两个数组元素和构成的新数组下的最小的k个数

pre

在看了大佬[1]这条题目的算法分析之后,发现有些东西大佬并没有写清楚。这里针对这位博主没有写清楚的两个问题,我进行细化阐述。

问题1:寻找数组中最小的第k个数

问题描述:输入一个长度为n的整数数组,希望获得最小的k个数。

算法1:直接做排序,然后取前n个,时间复杂度为 n*log(n),空间复杂度为O(1)

简单粗暴,但是如果n大,k相比n小的时候,这个算法就会存在很多时间浪费

算法2:构建大小为k的最大堆,最后只需要吐出堆顶元素就行了,时间复杂度为 O(n*log(k)),空间复杂度为O(k)

比起算法1,算法2采用了空间换时间的思路,在k远小于n的时候存在很大优势

算法3:采用快排的思路,随机选取一个元素做中间值,然后把后续所有元素放在该元素的左右两侧,根据左边元素个数选择在左侧还是右侧重复该行为,在左边元素个数为k-1的时候,中间元素就是我们需要的值。该算法的平均时间复杂度为O(n),空间复杂度为O(1)。(PS:这里的时间复杂度计算我不理解,但是肯定是优于算法1的完全排序)

算法3的实现可以参考该博主给出的代码[2],博客的内容与他给出的标题不符,但是他的代码是我预期的实现。

问题2:寻找两个数组元素和构成的新数组下的最小的k个数

问题简述:已知两个整数数组,数组之间任意两个元素之间的和,可以构成一个新的数组,求新数组下的最小的k个数。

问题分析:首先假设输入数组为a[] , b[],分别有n和m个元素。那么新生成的数组有n*m个元素,我们需要在这种情况下得出最小的k个数

算法1: 可以全部算出来,然后统一排序,取前k个数。时间复杂度为O(n*m * log(n*m)) ,空间复杂度为 O(n*m)
这样总感觉不太OK

算法2:采用最小堆来减少空间消耗,构建大小为k的最小堆,然后在计算生成值的时候动态插入到最小堆中,时间复杂度为O(n*m*log(k)),空间复杂度为O(k)
两条数组的性质没有被利用到,计算生成值的过程额定要消耗O(n*m)的时间。

算法3:首先对两个数组排序,假设n<m,我们可以得到n个有序队列

a[1]+b[1]<...<a[1]+b[m]
...
a[n]+b[1]<...<a[n]+b[m]

我们可以维护一个大小为n的最小堆,将每条有序队列的第一个元素插进去,最小堆的节点需要记录该元素来源的位置,以保证之后的动态跟新。每次取最小堆的堆顶元素,然后将该元素的原始数组的后一位插入进去(如果该序列用完了,那么堆的大小-1)。这样时间复杂度为O(m*log(m)),空间复杂度为O(n)

目前算法3是我能想到的最佳算法了,该算法参考了网上的思路[3],但是这篇文章的分析太粗糙了

post

欢迎大佬们给出新的算法思路

reference

[1] : https://www.kancloud.cn/kancloud/the-art-of-programming/41579
[2] : https://blog.csdn.net/u012614432/article/details/53244741
[3] : https://www.xuebuyuan.com/1482203.html

猜你喜欢

转载自blog.csdn.net/u010953266/article/details/81708884
今日推荐