选取重复频率最高前k个数

选取重复频率最高前k个数

题目描述

在一个无序的整数数组中选取重复频率最高的前k个数,例如:整数数组[3,4,5,6,4,3,5,2,3],k=3,则结果集为[3,5,4]。

题目解析

第一种方法暴力解法:对所有数的频率进行统计,然后用排序算法进行排序找出前k个频率最高的数。
如果我们按相对来说最优的排序算法快速排序来进行查找,快速排序代码如下:

public static void quickSort(int[] a,int left, int right){

                if (left >= right) {
                        return;
                }
                int v = a[left];
                int l = left + 1;
                int r = right;
                while (l < r) {

                        if (a[l] <= v) {
                                l++;
                                continue;
                        }
                        if (a[r] >= v) {
                                r--;
                                continue;
                        }
                        int temp = a[l];
                        a[l] = a[r];
                        a[r] = temp;
                        l++;
                        r--;

                }
                if (a[left] > a[l]) {

                        a[left] = a[l];
                        a[l] = v;
                }else {
                        a[left] = a[l - 1];
                        a[l - 1] = v;
                        l--;
                }

                quickSort(a,left,l-1);
                quickSort(a,l+1,right);
        }

快速排序的时间复杂度不低于nlogn,统计的时间复杂度为n,
所以这种方法的最终时间复杂度为O(nlogn),空间复杂度为O(n)。

第二种方法是利用堆排序:将统计频率用最小堆进行排序,设置堆的最大值,超过最大值时将小的频率替换,最后堆剩下的值就是频率最高的数值。
这里统计频率用map存储。代码如下:

//用map对数的频率进行统计
public static void conut(int[] a){
                int count = a.length;
                for (int i = 0; i < count; i++) {
                        if (countMap.containsKey(a[i])) {
                                countMap.put(a[i], countMap.get(a[i])+1);
                        }else {
                                countMap.put(a[i], 1);
                        }
                }
        }
//利用堆排序
        public static int[] dumpSort(Map<Integer,Integer> map,int k){

                conut(a);
                PriorityQueue<Integer> priorityQueue = new 	PriorityQueue(new Comparator<Integer>() {
                        @Override
                        public int compare(Integer o1, Integer o2) {
                                return map.get(o1) - map.get(o2);
                        }
                });
                for (Integer i : map.keySet()) {
                        if (priorityQueue.size() < k) {
                                priorityQueue.add(i);
                        } else if (map.get(priorityQueue.peek()) < map.get(i)) {
                                priorityQueue.remove();
                                priorityQueue.add(i);
                        }
                }
                int[] res = new int[k];
                for (int i = 0; i < k; i++) {
                        res[i] = priorityQueue.remove();
                }
                return res;
        }

这里维护堆的数目是k,操作的数量是n,堆是二叉树的形式,所以每次维护堆的时间复杂度为logk,又因为总量是n,所以排序的时间复杂度为O(nlogk)。统计频率的时间复杂度为O(n),所以总的时间复杂度为O(nlogk)。空间复杂度中因为维护频率的map需要n,堆的数量需要k,一共需要的空间复杂度为
n+k,记为O(n)。

第三种是最优的算法利用桶排序:将统计后频率相同的数值放进同一个桶里,最后倒着从大的桶里开始取值,取出的量达到k位置。这里用list数组来表示不同的桶,list[i]用所以i来表示频率,list[i]其中的数值表示其中该频率的数值有哪些。代码如下:

public static void conut(int[] a){
                int count = a.length;
                for (int i = 0; i < count; i++) {
                        if (countMap.containsKey(a[i])) {
                                countMap.put(a[i], countMap.get(a[i])+1);
                        }else {
                                countMap.put(a[i], 1);
                        }
                }
        }
       public static List<Integer> bucketSort(int k){

                conut(a);

                List<Integer> res = new ArrayList<>();

                List<Integer>[] lists = new List[countMap.size()];

                for (Integer key : countMap.keySet()) {
                        int i = countMap.get(key);
                        if (lists[i] == null) {
                                lists[i] = new ArrayList<>();
                        }
                        lists[i].add(key);
                }
                int length = lists.length;
                for (int i = length - 1; i >= 0 && res.size() < k; i--) {
                        if (lists[i] == null) {
                                continue;
                        }
                        res.addAll(lists[i]);
                }
                return res;
        }

这里只需要遍历一次即可,所以时间复杂度为n,统计频率的时间复杂度为n,所以最终时间复杂度表示为O(n)。每个数值只重复储存了一次,所以空间复杂度为O(n)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值