剑指 Offer 40. 最小的k个数
*215. 数组中的第K个最大元素
*347. 前 K 个高频元素
在未排序的数组中找到第 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大元素是排序后从后往前数第K个,排序后返回 nums.length-k 位置的元素,当然直接Arrays.sort()也可以
class Solution {
public int findKthLargest(int[] nums, int k) {
//插入排序
for(int i=1; i<nums.length; i++){
int temp = nums[i]; //暂存要插入的元素
int j = i;
while( j>0 && temp<nums[j-1]){
nums[j] = nums[j-1]; //如果要插入的元素小于当前元素,当前元素后移
j--;
}
nums[j] = temp; //找到要插入的位置,插入元素
}
return nums[nums.length-k];
}
}
维护一个大小<=k的有序队列,如果队列中元素的个数<=k时就add,个数>k时把最顶端的元素poll出队,因为是优先队列,所以移除的就是队列中最小的值
class Solution {
public int findKthLargest(int[] nums, int k) {
final PriorityQueue<Integer> queue = new PriorityQueue<>();
for (int val : nums) {
queue.add(val);
if (queue.size() > k)
queue.poll();
}
return queue.peek();
}
}
利用小顶堆的特性(堆顶元素最小),先对前K个数组元素进行"原地"建小顶堆,建完小顶堆后,堆顶的元素最小,正好是这K个元素的第K大元素。
然后遍历剩下的元素 nums[k] ~ nums[len-1],一直维护这个有K个元素的小顶堆,最后的小顶堆就是原数组第K大元素到第最大元素,堆顶就是第K大元素
class Solution {
public int findKthLargest(int[] nums, int k) {
buildHeap(nums, k); //先用前k个元素原地建堆
//遍历剩下元素,比堆顶小,跳过;比堆顶大,交换后重新堆化
for(int i=k; i<nums.length; i++){
if(nums[i] < nums[0]){
continue;
}
swap(nums, i, 0);
heapify(nums, k, 0);
}
//K个元素的小顶堆的堆顶即是第K大元素
return nums[0];
}
//建堆,从倒数第一个非叶子节点开始堆化,倒数第一个非叶子节点下标为 K/2-1
public void buildHeap(int[] a, int k){
for(int i=k/2-1; i>=0; i--){
heapify(a, k, i);
}
}
//堆化
//父节点下标i,左右子节点的下标分别为 2*i+1 和 2*i+2
public void heapify(int[] a, int k, int i){
int min = i; //临时变量 minPos 用于存储最小值的下标,先假设父节点最小
while(true){
if(i*2+1<k && a[i*2+1]<a[i]){
//和左子节点比较
min = i*2+1;
}
if(i*2+2<k && a[i*2+2]<a[min]){
//和右子节点比较
min = i*2+2;
}
if(min==i){
//如果minPos没有发生变化,说明父节点已经是最小了,直接跳出
break;
}
swap(a, i, min); //否则交换
i = min; //父节点下标进行更新,继续堆化
}
}
public void swap(int[] a, int n, int m){
int temp = a[n];
a[n] = a[m];
a[m] = temp;
}
}
建立一个大根堆,做 k - 1 次删除操作后堆顶元素就是要找的答案
class Solution {
public int findKthLargest(int[] nums, int k) {
int heapSize = nums.length;
buildMaxHeap(nums, heapSize);
for (int i = nums.length - 1; i >= nums.length - k + 1; --i) {
swap(nums, 0, i);
--heapSize;
maxHeapify(nums, 0, heapSize);
}
return nums[0];
}
public void buildMaxHeap(int[] a, int heapSize) {
for (int i = heapSize / 2; i >= 0; --i) {
maxHeapify(a, i, heapSize);
}
}
public void maxHeapify(int[] a, int i, int heapSize) {
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
if (l < heapSize && a[l] > a[largest]) {
largest = l;
}
if (r < heapSize && a[r] > a[largest]) {
largest = r;
}
if (largest != i) {
swap(a, i, largest);
maxHeapify(a, largest, heapSize);
}
}
public void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
第k大元素也是第 N-K 小元素,利用快排的性质不断缩小范围
class Solution {
public int findKthLargest(int[] nums, int k) {
int size = nums.length;
// kth largest is (N - k)th smallest
return quickselect(nums, 0, size - 1, size - k);
}
public void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
public int partition(int[] nums, int left, int right, int pivot_index) {
int pivot = nums[pivot_index];
// 1. move pivot to end
swap(nums, pivot_index, right);
int store_index = left;
// 2. move all smaller elements to the left
for (int i = left; i <= right; i++) {
if (nums[i] < pivot) {
swap(nums, store_index, i);
store_index++;
}
}
// 3. move pivot to its final place
swap(nums, store_index, right);
return store_index;
}
public int quickselect(int[] nums, int left, int right, int k_smallest) {
/*
Returns the k-th smallest element of list within left..right.
*/
if (left == right) // If the list contains only one element,
return nums[left]; // return that element
// select a random pivot_index
Random random_num = new Random();
int pivot_index = left + random_num.nextInt(right - left);
pivot_index = partition(nums, left, right, pivot_index);
// the pivot is on (N - k)th smallest position
if (k_smallest == pivot_index)
return nums[k_smallest];
// go left side
else if (k_smallest < pivot_index)
return quickselect(nums, left, pivot_index - 1, k_smallest);
// go right side
return quickselect(nums, pivot_index + 1, right, k_smallest);
}
}