栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

215. 数组中的第K个最大元素(优先队列,堆排序)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

215. 数组中的第K个最大元素(优先队列,堆排序)

215. 数组中的第K个最大元素

优先队列的思路是很朴素的。由于找第 K 大元素,其实就是整个数组排序以后后半部分最小的那个元素。因此,我们可以维护一个有 K 个元素的最小堆:

如果当前堆不满,直接添加;
堆满的时候,如果新读到的数小于等于堆顶,肯定不是我们要找的元素,只有新遍历到的数大于堆顶的时候,才将堆顶拿出,然后放入新读到的数,进而让堆自己去调整内部结构。
说明:这里最合适的操作其实是 replace(),即直接把新读进来的元素放在堆顶,然后执行下沉(siftDown())操作。Java 当中的 PriorityQueue 没有提供这个操作,只好先 poll() 再 offer()。

k很小,就用大根堆; k很大,就用小根堆
class Solution {
    public int findKthLargest(int[] nums, int k) {
        int len = nums.length;
        PriorityQueue minHeap = new PriorityQueue<>((a, b) -> a - b);
        for (int i = 0; i < k; i++) {
            minHeap.offer(nums[i]);
        }
        for (int i = k; i < len; ++i) {
            Integer topElement = minHeap.peek();
            if (nums[i] > topElement) {
                minHeap.poll();
                minHeap.offer(nums[i]);
            }
        }
        return minHeap.peek();
    }
}
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 使用小顶堆
        PriorityQueue pq = new PriorityQueue<>(k);
        for (int num : nums) {
            if (pq.size() < k) {
                pq.offer(num);
            } else if (pq.peek() < num) {
                pq.poll();
                pq.offer(num);
            }
        }
        return pq.peek();
    }
}
class Solution {
    public int findKthLargest(int[] nums, int k) {
    PriorityQueue pq = new PriorityQueue<>((a, b) -> b - a);
    for (Integer num : nums) {
        pq.add(num);
    }
    for (int i = 0; i < k - 1; i++) {
        pq.remove();
    }
        return pq.peek();
    }
}
使用数组建堆
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 使用数组构建小顶堆
        int[] top = new int[k];
        // 将 nums 数组中的前 k 个元素取出来
        for (int i = 0; i < k; i++) {
            top[i] = nums[i];
        }
        // 先建堆,然后依次比较剩余元素与堆顶元素的大小,比堆顶大的,说明它应该在堆中出现,则用它来替换掉堆顶元素,然后沉降。
        buildHeap(top);
        for (int j = k; j < nums.length; j++) {
            int temp = top[0];
            if (temp < nums[j]) {
                setTop(top, nums[j]);
            }
        }
        return top[0];
    }

    // 建堆
    public void buildHeap(int[] nums) {
        // 最后一个节点
        int lastNode = nums.length - 1;
        // 找到最后一个节点的父节点
        int startHeapify = (lastNode - 1) / 2;
        for (int i = startHeapify; i >= 0; i--) {
            // 不断调整建堆
            heapify(nums, i, nums.length);
        }
    }

    // 不断调整小顶堆
    public void heapify(int[] nums, int index, int length) {
        // 左右子节点
        int left = (index << 1) + 1;
        int right = (index << 1) + 2;
        // 假定当前节点最小
        int min = index;
        // 比较左右子节点找到最小值
        if (left < length && nums[left] < nums[min]) {
            min = left;
        }
        if (right < length && nums[right] < nums[min]) {
            min = right;
        }
        // 如果不相等就需要交换
        if (min != index) {
            swap(nums, min, index);
            // 递归调用
            heapify(nums, min, length);
        }
    }

    // 交换数组元素
    public void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

    // 将堆顶元素进行更换,继续进行沉降
    public void setTop(int[] nums, int top) {
        nums[0] = top;
        heapify(nums, 0, nums.length);
    }
}
快排
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return getTopK(nums, k);
    }

    // 分治
    public int partition(int[] nums, int low, int high) {
        int pivot = nums[low];
        while (low < high) {
            while (low < high && nums[high] <= pivot) {
                high--;
            }
            nums[low] = nums[high];
            while (low < high && nums[low] >= pivot) {
                low++;
            }
            nums[high] = nums[low];
        }
        nums[low] = pivot;
        return low;
    }

    // 获得 Kth 的数
    public int getTopK(int[] nums, int k) {
        int low = 0;
        int high = nums.length - 1;
        // 不断调整分治的位置,直到 position = k - 1
        while (true) {
            int index = partition(nums, low, high);
            if (index == k - 1) {
                return nums[index];
            }
            else if (index < k - 1) {
                low = index + 1;
            }
            else {
                high = index - 1;
            }
        }
    }
}
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return getTopK(nums, k);
    }

    private static void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    private static int partition(int[] nums, int l, int r) {
        // 取分界点
        int x = nums[l];
        int i = l + 1, j = r;
        while (true) {
            while (i < r && nums[i] > x) i++;
            while (j > l && nums[j] < x) j--;
            if (i >= j) break;
            swap(nums, i, j);
            i++;
            j--;
        }
        swap(nums, l, j);
        return j;
    }


    // 获得 Kth 的数
    private static int getTopK(int[] nums, int k) {
        int l = 0, r = nums.length - 1;
        // 不断调整分治的位置,直到 position = k - 1
        int index = partition(nums, l, r);
        while (index != k - 1) {
            if (index > k - 1) {
                r = index - 1;
                index = partition(nums, l, r);
            } else if (index < k - 1) {
                l = index + 1;
                index = partition(nums, l, r);
            }
        }
        return nums[index];
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/749099.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号