zoukankan      html  css  js  c++  java
  • 最小的k个数

    题目:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,

    求最大的k个数用最小堆,根节点是堆 的最小值,每次和根节点比较,比根小,舍弃,否则,代替根

    求最小的K个数用最大堆,根节点是堆的最大值,每次和根节点比较,比根大,舍弃,否则,代替根。

    PriorityQueue 是默认小根堆,根节点是最小值。所以用来求解最大的k个数

    public static List<Integer> findKthLargest(int[] nums, int k) {
            PriorityQueue<Integer> minQueue = new PriorityQueue<>(k);
            for (int num : nums) {
                if (minQueue.size() < k || num > minQueue.peek())
                    minQueue.add(num);
                if (minQueue.size() > k)
                    minQueue.poll();
            }
      
          return new ArrayList<>(minQueue);
    }

    本题解法:PriorityQueue 是可以指定为大根堆,根节点是最大值。所以用来求解最小的k个数

    public static List<Integer> solutionByHeap(int[] input, int k) {
            List<Integer> list = new ArrayList<>();
            if (k > input.length || k == 0) {
                return list;
            }
          //指定为大根堆。 PriorityQueue
    <Integer> queue = new PriorityQueue<>(Comparator.reverseOrder()); //得到k个最大值 for (int num : input) { if (queue.size() < k) { queue.add(num); } else if (queue.peek() > num){ queue.poll(); //移除头元素,也就是最大值 queue.offer(num); } }
          return new ArrayList<>(minQueue);
     }

    本题解法:手写大根堆,前k个元素是最小的k个元素 为什么从n/2开始建堆呢,因为n/2是最后一个非叶子节点。n/2到n的所有节点都是叶子节点,是最下一层,不需要下沉。比如n=9 树的编号是{[1],[2,3],[4,5,6,7],[8,9]}。n/2=4就是第三层的第一个节点,也是最后一个非叶子节点。

    /* 维护 A[0...k-1] 这个大根堆 */
        public static List<Integer> topKSmall(int A[], int n, int k)
        {
            //初始化前面k个元素
            for(int i=k/2; i>=0; --i)
                AdjustDown(A, i, k); // 先用前面的k个数建大根堆
    
            // 从k开始向后遍历,一直到结束,比如k=3,n可能是很大很大。
            for(int i=k; i<n; ++i)
            {
                if(A[i] < A[0])  // 如果小于堆顶元素,替换之
                {
                    int tmp = A[0];
                    A[0] = A[i];
                    A[i] = tmp;
                    AdjustDown(A, 0, k);  // 向下调整
                }
            }
            ArrayList<Integer> result = new ArrayList<Integer>();
            for (int i = 0; i < k; i++) {
                result.add(A[i]);
            }
            return result;
        }
    
        /**
         *
         * @param arr
         * @param parentIndex
         * @param length   指的是堆的有效大小。只在这个范围内下沉
         */
        public static void AdjustDown(int arr[], int parentIndex, int length)
        {
            int temp = arr[parentIndex];
            int childIndex = 2 * parentIndex +1;
            while (childIndex<length) {
                if (childIndex+1<length && arr[childIndex+1]>arr[childIndex]){
                    childIndex++;
                }
                if(temp>=arr[childIndex]) break;
    
                arr[parentIndex]=arr[childIndex];
                parentIndex=childIndex;
                childIndex=2*childIndex+1;
            }
            arr[parentIndex]=temp;
        }

    当求最大的k个数字时,只需要把大根堆换成小根堆即可。(下沉的判断条件反一下,入堆的判断条件也反一下)

    /* 维护 A[0...k-1] 这个小根堆 */
        public static List<Integer> topKBig(int A[], int n, int k)
        {
            //初始化前面k个元素
            for(int i=k/2; i>=0; --i)
                AdjustDown(A, i, k); // 先用前面的k个数建小根堆
    
            // 从k开始向后遍历,一直到结束,比如k=3,n可能是很大很大。
            for(int i=k; i<n; ++i)
            {
                if(A[i] > A[0])  // 如果大于堆顶元素,替换之
                {
                    int tmp = A[0];
                    A[0] = A[i];
                    A[i] = tmp;
                    AdjustDown(A, 0, k);  // 向下调整
                }
            }
            ArrayList<Integer> result = new ArrayList<Integer>();
            for (int i = 0; i < k; i++) {
                result.add(A[i]);
            }
            return result;
        }
    
        /**
         *
         * @param arr
         * @param parentIndex
         * @param length   指的是堆的有效大小。只在这个范围内下沉
         */
        public static void AdjustDown(int arr[], int parentIndex, int length)
        {
            int temp = arr[parentIndex];
            int childIndex = 2 * parentIndex +1;
            while (childIndex<length) {
                if (childIndex+1<length && arr[childIndex+1]<arr[childIndex]){
                    childIndex++;
                }
                if(temp<=arr[childIndex]) break;
    
                arr[parentIndex]=arr[childIndex];
                parentIndex=childIndex;
                childIndex=2*childIndex+1;
            }
            arr[parentIndex]=temp;
        }

    总结:大根堆的解法和堆排序几乎一样,只有两个地方不同,1:大根堆解法只需要对前k个元素建堆,堆排序要对所有元素建堆。2.大根堆解法每次替换堆定元素,堆排序每次是删除堆定元素,把它移到未排序部分 的最后一位

    //堆排序
    public static void heapSort(int[] arr){
            for(int i = arr.length/2;i>=0;i--){
                downAdjust(arr,i,arr.length);
            }
            System.out.println(Arrays.toString(arr));
    
            //删除堆顶的元素,就是把数组的第一位和最后一位换位置
            for (int i = arr.length-1;i>0;i--) {
                int temp = arr[i];
                arr[i]=arr[0];
                arr[0]=temp;
                downAdjust(arr,0,i); //然后把第一个元素下沉,在0到length的区间内
                System.out.println(Arrays.toString(arr));
            }
        }
        public static void downAdjust(int[] arr,int parentIndex,int length) {
            int temp = arr[parentIndex];
            int childIndex = 2 * parentIndex +1;
            while (childIndex<length) {
                if (childIndex+1<length && arr[childIndex+1]>arr[childIndex]){
                    childIndex++;
                }
                if(temp>=arr[childIndex]) break;
    
                arr[parentIndex]=arr[childIndex];
                parentIndex=childIndex;
                childIndex=2*childIndex+1;
            }
            arr[parentIndex]=temp;
        }
  • 相关阅读:
    Flink实例(117):FLINK-SQL应用场景(16)以upsert的方式读写Kafka数据——以Flink1.12为例(二)
    Flink实例(116):FLINK-SQL应用场景(15)以upsert的方式读写Kafka数据——以Flink1.12为例(一)
    数据挖掘实践(17):基础理论(十七)数据挖掘基础(四)模型解释
    数据挖掘实践(16):基础理论(十六)数据挖掘基础(三)特征工程(二)性能度量与评估方法
    rust 可变变量
    Rust学习(32):智能指针-Rc<T>
    rust 高级编程
    rust 所有权
    rust智能指针
    Anbox:容器中的 Android,anboxandroid
  • 原文地址:https://www.cnblogs.com/team42/p/6682928.html
Copyright © 2011-2022 走看看