寻找数组中出现次数超过一半的数
假设数组大小为N
1. 排序
复杂度为O(N * log2N)
2. 部分排序
选择排序和交换排序都是不错的选择。把N 个数中的前K 大个数排序出来,复杂度是O(N * K)。
3.
快排的每一步是随便选一个数a,将小于该数的放到前面,大于该数的放到后面,即将该数放到正确的位置.这时出现两种情况:
1) a以前的元素个数Sa<K, 则在a后面的元素中再选K-Sa个.
2) Sa中元素的个数大于或等于K,则需要返回Sa中最大的K个元素.
复杂度 O(N * log2K).
4.
寻找N个数中最大的K个数,本质上就是寻找最大的K个数中最小的那个,也就是第K大的数。可以使用二分搜索的策略来寻找n个数中的第K大的数。对于一个给定的数p,可以在O(N)的时间复杂度内找出所有不小于p 的数。假如n个数中最大的数为Vmax,最小的数为Vmin,那么这N个数中的第K大数一定在区间[Vmin, Vmax]之间。那么,可以在这个区间内二分搜索N个数中的第K大数p.伪代码如下:
while(Vmax – Vmin > delta) { Vmid = Vmin + (Vmax - Vmin) * 0.5; if(f(arr, N, Vmid) >= K) Vmin = Vmid; else Vmax = Vmid; }
上述伪代码中,f(arr, N, Vmid)返回数组arr[0, …, N-1]中大于等于Vmid 的数的个数。delta 的取值要比所有N 个数中的任意两个不相等的元素差值之最小值小。如果所有元素都是整数,delta 可以取值0.5。循环运行之后,得到一个区间(Vmin, Vmax),这个区间仅包含一个元素(或者多个相等的元素)。这个元素就是第K 大的元素。整个算法的时间复杂度为O(N * log2(|Vmax - Vmin|/delta))。由于delta 的取值要比所有N 个数中的任意两个不相等的元素差值之最小值小,因此时间复杂度跟数据分布相关。在数据分布平均的情况下,时间复杂度为O(N * log2N).
4.
上面3中方法都需要遍历数组多次,如果数组很大,甚至不能装入内存,就需要下面的方法:
建一个最小堆来存最大的K个数.扫描一遍数组,如果扫描到的元素比堆顶元素大,则更新堆.间复杂度为O(N * log2K)
浙公网安备 33010602011771号