Leetcode #347. Top K Frequent Elements 前K高频数 解题报告

1 解题思想

这道题呢,给了一个非空数组一个数字k,现在需要你找出出现频率最高的K个数,其中
1、请你假设解释一定存在的,并且是唯一的
2、运行时间要求小于 O(n log n),
这道题会拆解成两部分:
1、首先将数组用哈希HashMap统计其数字频率,并转化成数组
2、利用类似于快排的方式,找到第k大的频率的开始范围

自此以后,就可以将其遍历输出。

现在题目比较新,暂时没有时间可以比较,但是AC了,从原理上说我这个寻找K不是严格的O(n),如果超时解决方法如下:
1、可以尝试使用随机快排的思想,在寻找k的时候进行一下随机化
2、使用Select算法代替,这个严格证明的是O(n)但是这个太复杂,原算法可以参考北京大学屈婉玲老师的算法分析与设计,我是最开始见于那本书上的。

2 原题

Given a non-empty array of integers, return the k most frequent elements.

For example,
Given [1,1,1,2,2,3] and k = 2, return [1,2].

Note:

•You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
•Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.

3 AC解


public class Solution {
    /** * 这道题将会先找到第K大的数(O(n)),然后遍历(O(n)) * * 寻找第K大的数,可以进行划分(有一种叫做Select的算法,将数字进行5组划分成一起,然后中位数。。那个很复杂),然后另外一种是接近于快排的,他的平均复杂度为O(n),最坏就是O(n^2)了,我先试试这种 * */

    public void swap(int[] nums,int a,int b){
        int tmp=nums[a];
        nums[a]=nums[b];
        nums[b]=tmp;
    }
    /** * 寻找到第K大的位置的频率,近似与快排 * */
    public int findK(int[] nums,int k){
        int start=0,end=nums.length-1;
        while(start<=end){
            int i=start,j=end;
            while(i<j){
                while(i<j && nums[j]>=nums[i]) j--;
                swap(nums,i,j);
                while(i<j && nums[i]<=nums[j]) i++;
                swap(nums,i,j);
            }
            if(i==k-1)
                return nums[i];
            if(i<k-1)
                start=i+1;
            else end=i-1;
        }
        return 0;
    }
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> list = new ArrayList<Integer>();
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(nums[i])==false) map.put(nums[i],0);
            map.put(nums[i],map.get(nums[i])+1);
        }
        Iterator<Map.Entry<Integer,Integer>> it = map.entrySet().iterator();
        int items[] =new int[map.size()];
        int fre[] =new int[map.size()];
        int b_fre[] =new int[map.size()];
        int count=0;
        while(it.hasNext()) {
            Map.Entry<Integer,Integer> entry= it.next();
            items[count] = entry.getKey();
            fre[count] = entry.getValue();
            b_fre[count++] = entry.getValue();
        }
        //注意这里的寻找k,因为我们是找前k个最大的,所以等同于我要找到第b_fre.length-k小的位置
        int index=findK(b_fre,b_fre.length-k);
        for(int i=0;i<fre.length;i++){
            if(fre[i]> index)
                list.add(items[i]);
        }
        return list;
    }
}

4 题外话

首先说个题外话,因为感觉Leetcode编号靠后的这些解析不是很多,可能比较容易被索引到,所以可能会乱序的出一些报告,见谅

本博客可能会在我的新浪微博@MebiuW 和 个人网站同步(www.zerodigeek.com),只是可能略微延后,网站也在重建当中

你可能感兴趣的:(LeetCode,HashMap,遍历,快速排序,词频)