难度:中等
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2 输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
力扣:
https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
解题思路:
基于小顶堆思路,先用K个数字建立小顶堆,
然后遍历数组,对比数组当前值与小顶堆堆顶元素的值,
若大于,替换堆顶元素,调整堆结构。
代码:
package com.ziling.goodlife.study; /** * @Author: yipeng * @Date: 2021/6/21 20:28 */ public class TopK { /** * 最小堆的结构调整 * @param arr 数组 * @param index 结束位置 */ private static void adjustHeap(int[] arr, int index) { // 获取父节点坐标 for (int i = index / 2; i > 0; i--) { // 记录父节点值(遍历过程中,第一次执行到此处时,记录父节点的值,相当于一个temp,只用于记录值。该值最终会替换掉遍历过程中最小的那个值) int parentVal = arr[i]; // 记录父节点下标(该下标值,会在下面遍历中位置下推) int parentIndex = i; // 不超过index节点情况下,遍历该父节点下子节点情况。 while (parentIndex * 2 <= index) { // 获取当前父节点的左节点 int childIndex = parentIndex * 2; // 判断两个儿子节点的大小,获取较小的一个儿子节点(循环遍历较小的一个,最小的最后会被替换掉) if (childIndex != index && arr[childIndex] > arr[childIndex + 1]) { childIndex++; } // 较小子节点比父节点的值(相当于temp)大,说明该次遍历完成 if (parentVal < arr[childIndex]) { break; } else { // 子节点较小的值放到当前父节点下标位置 arr[parentIndex] = arr[childIndex]; } // 当前父节点下标位置下推到之前较小子节点下标位置(此处完成父节点的下标位置下推) parentIndex = childIndex; } // 将父节点的值(相当于temp)替换到父节点当前下标位置 arr[parentIndex] = parentVal; } } private static void print(int[] nums, int start) { for (int i = start; i < nums.length; i++) { System.out.print(nums[i] + " "); } System.out.println(); } public static void main(String[] args) { int[] nums = {34,23,6435,4234,2523,425235,234234,6345,23,54,43,23,23,43,53,2,423,6345,432,24,25,2,234,53,6546,5345,2342,63534,234,4364}; int k = 10; int[] arr = new int[k + 1]; arr[0] = Integer.MAX_VALUE; print(nums, 0); System.arraycopy(nums, 0, arr, 1, k); print(arr, 1); // 建立小顶堆 adjustHeap(arr, k); print(arr, 1); for (int i = k; i < nums.length; i++) { // if (nums[i] > arr[1]) { arr[1] = nums[i]; adjustHeap(arr, k); } } print(arr, 1); } }
时间复杂度:O(k+nlog(k))
空间复杂度为:O( 1 )
参考快排:https://blog.csdn.net/longziling/article/details/118077299