215J. Kth Largest Element in an Array
https://leetcode.com/problems/kth-largest-element-in-an-array/
是佛佛作业题 215 和 973 一模一样 这个题当下最主要的是实现了对 priority queue 的学习 这是最直接的应用 除此之外,方法 2,是对 2way quicksort 的一个应用。
Method PQ
可以用 max heap
class Solution {
public int findKthLargest(int[] nums, int k) {
// Max Heap
PriorityQueue<Integer> heap = new PriorityQueue<>((n1, n2) -> n2 - n1);
for(int i = 0; i < nums.length; i++){
heap.offer(nums[i]);
}
int count = 0;
while(count < k - 1){
heap.poll();
count++;
}
return heap.poll();
}
}
不如用 min heap
class Solution {
public int findKthLargest(int[] nums, int k) {
// Min Heap
PriorityQueue<Integer> heap = new PriorityQueue<>((n1, n2) -> n1 - n2);
for(int i = 0; i < nums.length; i++){
heap.offer(nums[i]);
if(heap.size() > k){
heap.poll();
}
}
return heap.poll();
}
}
Method: Quick Select
第一次直接写了一个 two way quick sort
class Solution {
public int findKthLargest(int[] nums, int k) {
sort(nums,0, nums.length - 1);
return nums[k - 1];
}
public void swap(int[] a, int i, int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
return;
}
public void sort(int[] nums, int lo, int hi){
if(hi <= lo) return;
int j = partition(nums, lo , hi);
sort(nums,lo, j - 1);
sort(nums, j+ 1, hi);
}
public int partition(int[] nums, int lo, int hi){
int v = nums[lo];
int f = lo; // front pointer starts from lower bound
int b = hi + 1; //back pointer starts from upper bound
while(true){
while(nums[++f] > v ){
if(f == hi){
break;
}
}
while(nums[--b] < v){
if(b == lo){
break;
}
}
if(b <= f){
break;
}
swap(nums, b, f);
}
swap(nums, lo, b);
return b;
}
}
Quick Select
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
private int quickSelect(int[] nums, int left, int right, int targetIndex) {
if(left == right) return nums[left];
int randomPickedIndex = left + (int) Math.floor(Math.random() * (right + 1 - left));
int pivotIndex = partition(nums, left, right, randomPickedIndex);
if(pivotIndex == targetIndex) {
return nums[pivotIndex];
} else if (pivotIndex < targetIndex) {
return quickSelect(nums, pivotIndex + 1, right, targetIndex);
}
return quickSelect(nums, left, pivotIndex - 1, targetIndex);
}
private int partition(int[] nums, int left, int right, int randomPickedIndex) {
int pivotVal = nums[randomPickedIndex];
int curIndex = left;
swap(nums, right, randomPickedIndex);
for(int i = left; i < right; i++) {
if(nums[i] < pivotVal) {
swap(nums, curIndex, i);
curIndex++;
}
}
swap(nums, curIndex, right);
return curIndex;
}
private void swap(int[] nums, int i, int j) {
if (i == j) {
return;
}
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
}
// 大致知道啥意思了
// 就是说我们还是搞快排那一套,选一个分界点,然后把比它小的都扔到他左侧去。
// 我们想要第 k 大的,实际上是 第 N - k + 1 小的。不过 index 正好是 N - k。
// partition 干的事儿就是把用以分割数组的那个数先扔到子数组末尾,然后我们把比它小的都扔到最左侧,
// 然后把它回到该回的位置。
// 一旦我们发现我们把一个比它小的数都扔到他左边之后,它的 index == N - k, 那我们就知道找到了。
// 如果 index > N - k, 找左侧子数组,
// 如果 index < N - k 找右侧子数组。
// Quick Select 是为 这个题而生的,它不需要完成全部的排序,有很大可能早早返回正确值。
// 最差的情况就是老老实实的排序O(N^2)了一遍。
// worst case O(N^2)
// on average O(N)
// 补充一个产生随机数
// import java.util.Random;
// Random random = new Random();
// random.nextInt(right - left); 会 产生一个 [0, right - left - 1] 的数字。
下面放一个 3-way quickSelect
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
private int quickSelect(int[] nums, int start, int end, int targetIndex) {
if (start == end) return nums[start];
int randomPickIndex = start + (int) Math.floor(Math.random() * (end - start + 1));
randomPickIndex = partition(nums, start, end, randomPickIndex);
if (randomPickIndex == targetIndex) {
return nums[randomPickIndex];
} else if (randomPickIndex < targetIndex) {
return quickSelect(nums, randomPickIndex + 1, end, targetIndex);
} else {
return quickSelect(nums, start, randomPickIndex - 1, targetIndex);
}
}
private int partition(int[] nums, int start, int end, int pivotIndex) {
int pivot = nums[pivotIndex];
swap(nums, pivotIndex, end);
int lo = start;
int hi = end - 1;
int cur = start;
while (cur <= hi) {
if (nums[cur] == pivot) {
cur++;
} else if (nums[cur] < pivot) {
swap(nums, cur, lo);
lo++;
cur++;
} else {
swap(nums, cur, hi);
hi--;
}
}
swap(nums, cur, end);
return cur;
}
private void swap(int[] nums, int i, int j) {
if (i == j) return;
nums[i] ^= nums[j];
nums[j] ^= nums[i];
nums[i] ^= nums[j];
}
}
Last updated
Was this helpful?