有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度
,空间复杂度
数据范围:
,
,数组中每个元素满足
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
[1,3,5,2,2],5,3
2
[10,10,9,9,8,7,5,6,4,3,4,2],12,3
9
去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public int findKth (int[] a, int n, int K) {
// write code here
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int i = 0; i < n; i++) {
if(pq.size()<K){
pq.offer(a[i]);
}else{
if(a[i]>pq.peek()){
pq.poll();
pq.offer(a[i]);
}
}
}
return pq.peek();
}
}
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*/
public int findKth (int[] a, int n, int K) {
// write code here
// 快速排序 划分的思想
int i = 0, j = n - 1, k;
while (true) {
k = partition(a, i, j);
if (k == K - 1) return a[k];
else if (k < K - 1) i = k + 1;
else j = k - 1;
}
// qsort(a, 0, n - 1); // 验证快排成功
// return a[K - 1];
}
// 快排
public void qsort(int[] a, int i, int j) {
if (i >= j) return;
int k = partition(a, i, j);
qsort(a, i, k - 1);
qsort(a, k + 1, j);
}
// 快排的一次划分 [确定一个数的最终位置]
public int partition(int[] a, int i, int j) { // i大 --- 小j
int k = i;
while (i <= j) {
while (i <= j && a[i] >= a[k]) i++; // 都带=
while (i <= j && a[j] <= a[k]) j--;
if (i <= j) {
a[i] ^= a[j] ^ (a[j] = a[i]); // 交换a[i] a[j]
}
}
a[j] ^= a[k] ^ (a[k] = a[j]); // 交换a[j] a[k]枢轴
return j; // i不行
}
} import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public int findKth (int[] a, int n, int K) {
// write code here
// 1.先进行排序 - O(NlogN)
// 手写快排
// Arrays.sort(a);
quickSort(a);
// 2.直接取出第K大元素返回
return a[n - K];
}
// 快速排序主方法
public void quickSort(int[] a) {
if (a.length == 0 || a.length == 1) {
return;
}
process(a, 0, a.length - 1);
}
// 快速排序递归方法
public void process(int[] a, int l, int r) {
// 递归出口
if (l >= r) {
return;
}
// 先分区,再根据pivort的位置左右递归
int[] i = partition(a, l, r);
process(a, l, i[0]);
process(a, i[1], r);
}
// 快速排序分区方法
public int[] partition (int[] a, int l, int r) {
int p = a[l];
int smaller = l - 1;
int larger = r + 1;
int i = l;
while (i < larger) {
if (a[i] == p) {
// 当前值等于p,则直接掠过
i++;
} else if (a[i] < p) {
// 发现当前值比p更小,则与smaller的下一个位置交换,smaller自增,表示小于区右扩一位
// 同时i可以自增,因为从前面交换过来的元素要么等于p,要么是自己交换自己,无需再次比较
int t = a[i];
a[i] = a[smaller + 1];
a[smaller + 1] = t;
smaller++;
i++;
} else {
// 发现当前值比p更大,则与larger的前一个位置交换,larger自减,表示大于区左扩一位
// 此时i不能自增,因为从后面交换过来的元素不知道其与p的大小关系,需要再次比较
int t = a[i];
a[i] = a[larger - 1];
a[larger - 1] = t;
larger--;
}
}
int[] result = {smaller, larger};
return result;
}
} import java.util.*;
public class Solution {
public int findKth (int[] a, int n, int K) {
int[] nums = new int[10000001];
int max = 0;
int index = 0;
int count = 0;
for(int num: a) {
nums[num] += 1;
max = num > max? num: max;
}
for(index = max; index >= 0; index --) {
count += nums[index];
if(count >= K) break;
}
return index;
}
}
时间复杂度为2n的方法,nums的大小取决于a中值的限值范围
public int findKth (int[] a, int n, int K) {
// write code here
int[] heap = new int[K];
for (int i = 0; i < n; i++) {
if (i < K) {
heap[i]= a[i];
heapInsert(heap, i);
} else {
if (a[i] <= heap[0]) {
continue;
}
heap[0] = a[i];
adjust(heap);
}
}
return heap[0];
}
private static void heapInsert(int[] arr, int index) {
while (arr[index] < arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
private static void adjust(int[] heep) {
int index = 0;
int left = 2 * index + 1;
while (left < heep.length) {
int smaller = left + 1 < heep.length && heep[left + 1] < heep[left] ? left + 1 : left;
int minimum = heep[index] < heep[smaller] ? index : smaller;
if (minimum == index) {
break;
}
swap(heep, index, minimum);
index = minimum;
left = 2 * index + 1;
}
}
private static void swap(int[] heep, int a, int b) {
int temp = heep[a];
heep[a] = heep[b];
heep[b] = temp;
} public class Solution {
/**
* 有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
*
*
* @param a int整型一维数组
* @param n int整型
* @param k int整型
* @return int整型
*/
public int findKth (int[] a, int n, int k) {
if (n < k || k == 0) {
return -1;
}
quickSort(a, 0, n - 1);
return a[n - k];
}
public void quickSort(int[] a, int start, int end) {
int low = start;
int high = end;
int reference = a[start];
if (low >= high) {
return;
}
while (low < high) {
while (a[low] <= reference && low < end) {
low++;
}
while (a[high] >= reference && high > start) {
high--;
}
if (low < high) {
swap(a, low, high);
}
}
swap(a, start, high);
quickSort(a, start, high - 1);
quickSort(a, high + 1, end);
}
public void swap(int[] a, int low, int high) {
int temp = a[low];
a[low] = a[high];
a[high] = temp;
}
} import java.util.*;
public class Solution {
private class Node {
public int val;
public Node next = null;
}
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public int findKth (int[] a, int n, int k) {
// write code here
Node head = new Node();
Node now = head;
Node next;
int i = 1;
head.val = a[0];
// 构建最小堆,这里构建的是一个有序的链表,方便移动head
for (; i < k; i++) {
Node aaa = new Node();
aaa.val = a[i];
if (a[i] >= head.val) {
now = head;
next = now.next;
while (next != null) {
if (a[i] <= next.val) {
break;
}
now = next;
next = next.next;
}
now.next = aaa;
aaa.next = next;
} else {
aaa.next = head;
head = aaa;
}
}
// 和head比较:如果比head小就不用管,如果比head大,就看看是插入最小堆中哪里。注意如果插入,head需要往后移
for (; i < n; i++) {
Node aaa = new Node();
aaa.val = a[i];
if (a[i] > head.val) {
now = head;
next = now.next;
while (next != null) {
if (a[i] <= next.val) {
break;
}
now = next;
next = next.next;
}
now.next = aaa;
aaa.next = next;
head = head.next;
}
}
return head.val;
}
} import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public int findKth (int[] a, int n, int K) {
// write code here
return QuickSort(a, 0, n - 1, K);
}
public int QuickSort(int[] a, int low, int high, int K) {
int i = low;
int j = high;
int temp = a[i];
while (i < j) {
while (i < j && a[j] <= temp) j--;
a[i] = a[j];
while (i < j && a[i] >= temp)i++;
a[j] = a[i];
}
a[i] = temp;
if (i + 1 < K) {
return QuickSort(a, i + 1, high, K);
} else if (i + 1 > K) {
return QuickSort(a, low, i - 1, K);
} else {
return a[i];
}
}
}
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
shuffle(a,n);
int l=0;
int r=n-1;
K=n-K;
while(l<=r){
int p=partition(a,l,r);
if(p<K){ //p太小了
l=p+1;
}else if(p>K){
r=p-1;
}else{
return a[p];
}
}
return -1;
}
public void shuffle(int[] a,int n){
Random rand=new Random();
for(int i=0;i<n;i++){
int r=i+rand.nextInt(n-i);
swap(a,i,r);
}
}
public void swap(int[] a,int i,int j){
int tmp=a[i];
a[i]=a[j];
a[j]=tmp;
}
public int partition(int[] a,int l,int r){
int i=l;
int j=r;
int ppp=a[l];
while(i<j){
while(i<r&&a[i]<=ppp){
i++;
}
while(j>l&&a[j]>=ppp){
j--;
}
if(i>=j){ //注意这里的break
break;
}
swap(a,i,j);
}
swap(a,j,l);//为啥是j和l
return j;
}
} public int findKth(int[] a, int n, int K) {
Arrays.sort(a);
return a[n-K];
} public class Solution {
public int findKth(int[] a, int n, int K) {
// 归并排序
//merge(a, 0, n - 1);
//return a[K - 1];
// 堆排序
return heapSort(a, n, K);
}
public void merge(int [] input, int left, int right){
if(left >= right) return;
int mid = left + (right - left) / 2;
merge(input, left, mid);
merge(input, mid + 1, right);
int[] tempArr = new int[input.length];
int temL = left,tempR = mid + 1,tempArrIndex = 0;
while (temL <= mid && tempR <= right){
if(input[temL] <= input[tempR]){
tempArr[tempArrIndex] = input[tempR];
tempR++;
}else{
tempArr[tempArrIndex] = input[temL];
temL++;
}
tempArrIndex++;
}
while (temL <= mid){
tempArr[tempArrIndex] = input[temL];
temL++;
tempArrIndex++;
}
while (tempR <= right){
tempArr[tempArrIndex] = input[tempR];
tempR++;
tempArrIndex++;
}
tempArrIndex = 0;
for (int i = left; i <= right; i++) {
input[i] = tempArr[tempArrIndex];
tempArrIndex++;
}
}
public int heapSort(int[] arr, int n, int K){
for(int i = n / 2 - 1; i >= 0; i--) build(arr, i, n);
int temp;
for(int i = n - 1; i >= n - K; i--){
temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
build(arr, 0, i);
}
return arr[n-K];
}
public void build(int [] arr, int i, int len){
int temp = arr[i];
for(int k = i * 2 +1; k < len; k = k * 2 + 1){
if(k + 1 < len && arr[k] < arr[k+1]){
k++;
}
if(arr[k] > temp){
arr[i] = arr[k];
i = k;
}
}
arr[i] = temp;
}
} import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
quickSort(a,0,n-1);
return a[n-K];
}
public void quickSort(int[] arr,int left,int right){
int midIndex=(left+right)/2;
int midVal=arr[midIndex];
int l=left;
int r=right;
int temp;
while(l<r){
while(arr[l]<midVal){
l++;
}
while(arr[r]>midVal){
r--;
}
if(l>=r){
break;
}
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
if(arr[l]==midVal){
r--;
}
if(arr[r]==midVal){
l++;
}
}
if(l==r){
l++;
r--;
}
if(left<r){
quickSort(arr,left,r);
}
if(l<right){
quickSort(arr,l,right);
}
}
} import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
quickSort(a,0,n-1,n,K);
return a[n-K];
}
public void quickSort(int[] a,int left,int right,int n,int K){
if(left>=right)return;
int ref=a[left];
int l=left,r=right;
while(l<r){
while(a[r]>=ref&&l<r){
r--;
}
if(l<r){
a[l++]=a[r];
}
while(a[l]<=ref&&l<r){
l++;
}
if(l<r){
a[r--]=a[l];
}
}
a[l]=ref;
if(l==n-K){
return;
}else if(l>n-K){
quickSort(a,left,l-1,n,K);
}else{
quickSort(a,l+1,right,n,K);
}
}
}