无序数组中找top K 个值

在不增加空间复杂度的情况下,用堆排序。维护一个大小为k的堆。如果是找最大的K个值,那么用大顶堆,否则用小顶堆。
先从原数组中取k个值建立一个堆,然后每次从原数组中拿一个值与堆顶元素进行比较,看是否需要替换,如果替换了,就进行一次堆排序。这样到最后,这个堆中的元素就是top K。

前K大,维护最小堆;前K小,维护最大堆
1.初始化一个最小堆
2.输入新数据,若大于堆顶则替换堆顶,调整堆为最小堆(从最后一个父节点开始调整)
3.遍历完数据,遍历完数据,堆中数据即为所求
复杂度O(n*logK)

可以参考下面的代码。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int[] topK = new int[k];
        for(int i=0; i<k; i++){
            topK[i] = nums[i];
            System.out.println(topK[i]);
        }
        heapSort(topK);
        System.out.println(topK[0]);
        for(int j=k; j<nums.length; j++){
            if(nums[j]>topK[0]){
                topK[0] = nums[j];
                sort(topK, 0, k);
            }
        }
        return topK[0];
    }
    public void sort(int[] nums, int index, int size){
        int i = index;
        int j = 2*index+1;
        while(j<size-1){
            if(j<size-1 && nums[j]>nums[j+1])
                j++;
            if(nums[i]<nums[j])
                break;
            else{
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i = j;
                j = 2*i+1;
            }
        }
    }
    public void heapSort(int[] nums){
        for(int i=nums.length/2; i>=0; i--){
            sort(nums, i, nums.length);
        }
        // for(int i=1; i<nums.length; i++){
        //     int temp = nums[i];
        //     nums[i] = nums[nums.length-i+1];
        //     nums[nums.length-i+1] = temp;
        //     sort(nums, 1, nums.length-i);
        // }
    }
}

还有递归版的:

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> res=new ArrayList<>();
//      先用hashmap统计词频
        HashMap<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(nums[i])) {
                map.put(nums[i],map.get(nums[i])+1);
            }
            else {
                map.put(nums[i],1);
            }
        }
        int[] nums2=new int[map.size()];
        int index=0;
        for(Integer key:map.keySet()){
            nums2[index++]=map.get(key);
        }
//         对map中的词频提取前K
//         方法二:堆排序
        int []top=topK(nums2,k);        
//         找到词频对应的数(方法二)
        for(int i=0;i<k;i++){
//            map.keySet():返回set类型 map.values():collection类型
            for(Integer key:map.keySet()){
                if(map.get(key)==top[i]) {
                    if(res.size()==k) return res;
                    res.add(key);
//                    去重   map更新值:put方法覆盖原先数据
                    map.put(key,0);
                }
            }
        }
        return res;
    }    
//     方法二:堆排序
    //    调整堆 递归过程
    public void adjust(int nums[],int size,int index){
//        调整规则:比较父节点和子节点(left,right)
       int left=2*index+1;
       int right=2*index+2;
//       index为调整前父节点
       int min=index;
       if(left<size && nums[left]<nums[min]) min=left;
       if(right<size && nums[right]<nums[min]) min=right;
//       交换位置
        if(min!=index){
            int temp=nums[min];
            nums[min]=nums[index];
            nums[index]=temp;
//递归调整堆
            adjust(nums,size,min);
        }
    }
//    建堆
    public void buildHeap(int[] nums){
        int length=nums.length;
//        从length/2-1开始调整
        for(int i=length/2-1;i>=0;i--){
            adjust(nums,length,i);
        }
    }
//    查找topK
    public int[] topK(int[] nums,int k){
        int top[]=new int[k];
        for(int i=0;i<k;i++) top[i]=nums[i];
//        初始化堆
        buildHeap(top);
//        输入数据,更新堆
        for(int j=k;j<nums.length;j++){
            if(nums[j]>top[0]){
                top[0]=nums[j];
                adjust(top,k,0);
            }
        }
        return top;
    }
}

猜你喜欢

转载自blog.csdn.net/pnnngchg/article/details/88360373