18

力扣347——前 K 个高频元素

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU0NTk3NDMyMQ%3D%3D&%3Bmid=2247484052&%3Bidx=1&%3Bsn=cb37c01cc8ac0821edeab941402b8b6c
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

这道题主要涉及的是对数据结构里哈希表、小顶堆的理解,优化时可以参考一些排序方法。

原题

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

示例 1:

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

示例 2:

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

说明:

  • 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。

  • 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

原题url:https://leetcode-cn.com/problems/top-k-frequent-elements/

解题

正常思路

为了解决这道题,我们首先需要知道每个元素出现的次数。最方便的话,可以使用哈希表,因为这就是一个 数字——出现次数 的映射关系。此处的时间复杂度为 O(n)

其次,因为需要查找频率前 k 高的元素,所以我们肯定是需要排序的,时间复杂度为 O(n log n) 的排序方法有许多,快速排序、堆排序等,我是用的堆排序,使用 小顶堆 ,这样在每次入堆的时候,检查一下堆的个数是否超过 k,如果超过,则移除堆顶的元素(也就是次数最少的元素)。

这样堆里剩余的元素也就是最终的结果了,接下来我们看看代码:

class Solution {

    public List<Integer> topKFrequent(int[] nums, int k) {
        // 构建hashMap,记录每个元素出现的个数
        Map<Integer, Integer> countMap = new HashMap<>();
        for (int num : nums) {
            countMap.put(num, countMap.getOrDefault(num, 0) + 1);
        }

        // 利用PriorityQueue构建小顶堆
        PriorityQueue<Integer> heap = new PriorityQueue<Integer>((n1, n2) -> countMap.get(n1) - countMap.get(n2));
        Set<Integer> keySet = countMap.keySet();
        for (int key : keySet) {
            heap.add(key);
            // 如果个数大于k,则移除次数最少的数
            if (heap.size() > k) {
                heap.poll();
            }
        }

        List<Integer> result = new LinkedList<>();
        Iterator<Integer> iterator = heap.iterator();
        while (iterator.hasNext()) {
            result.add(iterator.next());
        }

        return result;
    }
}

提交OK。

桶排序优化

针对排序,我想到了一个优化,利用桶排序,其时间复杂度为 O(n) ,主要是浪费空间,因为需要申请额外的数组,下标代表出现的次数,元素我用的是 LinkedList,这样可以存储多个。那么这个在进行输出时,只要从后往前进行遍历,当结果的数量达到 k 时,就可以停止了。

接下来我们看看代码 :

class Solution {

    public List<Integer> topKFrequent(int[] nums, int k) {
        // 构建hashMap,记录每个元素出现的个数
        Map<Integer, Integer> countMap = new HashMap<>();
        // 记录最多的次数
        int maxCount = 0;
        for (int num : nums) {
            int count = countMap.getOrDefault(num, 0) + 1;
            if (count > maxCount) {
                maxCount = count;
            }
            countMap.put(num, count);
        }

        // 桶排序,构建数组,下标为重复的次数
        LinkedList[] array = new LinkedList[maxCount + 1];
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            int key = entry.getKey();
            int count = entry.getValue();
            LinkedList<Integer> list = array[count];
            if (list == null) {
                list = new LinkedList<>();
                array[count] = list;
            }
            list.add(key);
        }

        // 倒着遍历数组,直到找到K个元素
        List<Integer> result = new LinkedList<>();
        for (int i = array.length - 1; i >= 0 && result.size() < k; i--) {
            List<Integer> list = array[i];
            if (list == null) {
                continue;
            }

            result.addAll(list);
        }

        return result;
    }
}

提交OK。

总结

以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题主要涉及的是对数据结构的理解,优化时可以参考一些特殊的排序方法。

有兴趣的话可以访问我的博客或者关注我的公众号,说不定会有意外的惊喜。

https://death00.github.io/

公众号:健程之道

IZf6nqi.jpg!web

点击此处留言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK