TopK 问题

TopK 问题

数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。

示例 :

输入: [3, 2, 1, 5, 6, 4] 和 k = 2
输出: 5

堆:维护一个大小为 K 的最小堆, 最小堆中的元素就是第 K 大元素。

public int findKthLargest(int[] nums, int k) {
    // 一个基于优先级的无界优先级队列, 按照自然规律排序
    PriorityQueue<Integer> heap =  new PriorityQueue<Integer>(); 
    
    for (int n: nums) {
        heap.offer(n);
        if (heap.size() > k)  // 保持第K大元素在队列顶部
            heap.poll();
    }
    return heap.poll();        
}

快速选择:第 K 个元素的问题, 可以使用快速排序实现。

public int findKthLargest(int[] nums, int k) {
    int l = 0;
    int h = nums.length - 1;
    k = nums.length + 1 - k; //第 k 大 == 第 n + 1 - k 小
    while(l < h){
        int pos = partition(nums, l, h);
        if(pos == k - 1){
            break;
        } else if(pos < k - 1) {
            l = pos + 1;
        } else {
            h = pos - 1;
        } 
    }
    return nums[k - 1];
}

private int partition(int[] arr, int left, int right) {
    // 设定基准值(pivot)
    int pivot = arr[left];
    int i = left;
    int j = right;
    while(i < j) {
        // 从右向左找小于x的数来填s[i]
		while(i < j && s[j] >= x) {
            j--;
        }  
		if(i < j) {
			s[i] = s[j]; //将s[j]填到s[i]中, s[j]就形成了一个新的坑
			i++;
		}
 
		// 从左向右找大于或等于x的数来填s[j]
		while(i < j && s[i] < x) {
            i++;
        } 
		if(i < j) {
			s[j] = s[i]; //将s[i]填到s[j]中, s[i]就形成了一个新的坑
			j--;
		}        
    }
    arr[i] = pivot;
    return i;
}

前 K 个高频元素

给定一个非空的整数数组, 返回其中出现频率前 k 高的元素。

示例 :

输入: nums = [1, 1, 1, 2, 2, 3], k = 2
输出: [1, 2]

思路:设置若干个桶, 每个桶存储出现频率相同的数。桶的下标表示数出现的频率, 即第 i 个桶中存储的数出现的频率为 i。

把数都放到桶之后, 从后向前遍历桶, 最先得到的 k 个数就是出现频率最多的的 k 个数

public List<Integer> topKFrequent(int[] nums, int k) {
    //用于计数的map
    HashMap<Integer, Integer> count = new HashMap<Integer, Integer>();

    for(int num : nums) { //初始化每个元素出现的频率
        count.put(num, count.getOrDefault(num, 0) + 1);
    }

    //构建大顶堆
    PriorityQueue<Integer> heap = new PriorityQueue<Integer>((n1, n2) -> count.get(n1) - count.get(n2));

    for (int n : count.keySet()) {
        heap.add(n);
        if (heap.size() > k) {
            heap.poll();
        }
    }

    List<Integer> result = new LinkedList<>();
    while(!heap.isEmpty()) {
        result.add(heap.poll());
    }
    Collections.reverse(result); //反转
    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值