有一个整数数组,请你根据快速排序的思路,找出数组中第 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
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
if (K > n)
{
return -1;
}
quick_sort(a, 0, n-1);
return a[n-K];
}
void quick_sort(vector<int>& a, int iLow, int iUpper)
{
if (iLow >= iUpper)
{
return;
}
int iIndex = iLow;
int jIndex = iUpper;
int iBaseValue = a.at(iIndex);
while (iIndex < jIndex)
{
while(iIndex < jIndex && a.at(jIndex) >= iBaseValue)
{
jIndex--;
}
while (iIndex <jIndex && a.at(iIndex) <= iBaseValue)
{
iIndex++;
}
if (iIndex < jIndex)
{
std::swap(a[iIndex], a[jIndex]);
}
}
a[iLow] = a[iIndex];
a[iIndex] = iBaseValue;
quick_sort(a, iIndex+1, iUpper);
quick_sort(a, iLow, iIndex-1);
}
}; class Solution {
public:
vector<int> partition(vector<int> &a,int left,int right)
{
int less=left-1;
int more=right;
while(left<more)
{
if(a[left]<a[right])
{
swap(a[++less],a[left++]);
}
else if(a[left]>a[right])
{
swap(a[--more],a[left]);
}
else
{
left++;
}
}
swap(a[right],a[more]);
return {less+1,more};
}
void quicksort(vector<int> &a,int left,int right)
{
if(left>=right) return;
int index=left+rand()%(right-left+1);
swap(a[index],a[right]);
vector<int> recv=partition(a,left,right);
quicksort(a,left,recv[0]-1);
quicksort(a,recv[1]+1,right);
}
int findKth(vector<int> a, int n, int K) {
// write code here
quicksort(a,0,n-1);//注意传入的是n-1不是n
return a[n-K];
}
}; 手写快排
# -*- coding:utf-8 -*-
class Solution:
def quick_sort(self,a,left,right,k):
if left < right:
mid = self.partition(a,left,right)
if mid < k:
self.quick_sort(a,left,mid-1,k)
elif mid > k:
self.quick_sort(a,mid+1,right,k)
else:
return a
else:
return a
def partition(self,a,left,right):
pivot = left
while left != right:
while left < right and a[right] > a[pivot]:
right -= 1
while left < right and a[left] <= a[pivot]:
left += 1
if left < right:
a[left],a[right] = a[right],a[left]
a[pivot],a[left] = a[left],a[pivot]
return left
def findKth(self, a, n, K):
# write code here
return self.quick_sort(a,0,n-1,n-K)[n-K] # -*- coding:utf-8 -*- class Solution: def quick_sort(self,a,left,right,k): mid = self.partition(a,left,right) if mid == k: return a[mid] elif mid > k: return self.quick_sort(a,left,mid-1,k) elif mid < k: return self.quick_sort(a,mid+1,right,k) def partition(self,a,left,right): pivot = left while left != right: while left < right and a[right] > a[pivot]: right -= 1 while left < right and a[left] <= a[pivot]: left += 1 if left < right: a[left],a[right] = a[right],a[left] a[pivot],a[left] = a[left],a[pivot] return left def findKth(self, a, n, K): # write code here return self.quick_sort(a,0,n-1,n-K)
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
if (a == null || n == 0 || K < 1 || K > n){
return -1;
}
return partition(a, 0, n - 1, n - K);
}
private int partition(int[] a, int start, int end, int K) {
if (start >= end) {
return a[K];
}
int left = start, right = end;
int pivot = a[(start + end) / 2];
while (left <= right) {
while (left <= right && a[left] < pivot) {
left++;
}
while (left <= right && a[right] > pivot) {
right--;
}
if (left <= right) {
swap(a, left, right);
left++;
right--;
}
}
if (K <= right) {
return partition(a, start, right, K);
}
if (K >= left) {
return partition(a, left, end, K);
}
return a[K];
}
private void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
} import java.util.*;
public class Solution {
/** Partition Algorithm */
public static int partition(int[] a, int left, int right) {
int j = left;
int t = right;
while (j < t) {
if (a[j + 1] > a[j]) {
//swap a[j + 1] and a[j]
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
j = j + 1;
} else { // swap a[j + 1] and a[t]
int temp = a[j + 1];
a[j + 1] = a[t];
a[t] = temp;
t = t - 1;
}
}
return j;
}
/** QuickSort Algorithm*/
public static void QS(int[] a, int h, int k) {
int h1 = h;
int k1 = k;
// invariant a[h..k] is sorted if a[h1..k1] is sorted
while (k1 - h1 > 0) { // when a[h1..k1] has more than one element
int j = partition(a, h1, k1);
// a[h1..j-1] >= a[j] >= a[j+1..k1]
if (j - h1 < k1 - j) { // if a[h1..j-1] smaller than a[j+1..k1]
QS(a, h1, j - 1);
h1 = j + 1;
} else {
QS(a, j + 1, k1);
k1 = j - 1;
}
}
}
public int findKth(int[] a, int n, int K) {
QS(a, 0, n - 1);
return a[K - 1];
}
} 1.设置初始查找区间 low=0;high=n-1; 2.以ai为轴值对序列a[low]-a[high]进行一次划分,得到轴值的位置s 3.以轴值位置s与k进行比较 3.1 如果k-1等于s,则将as作为结果返回 3.2 如果s<k-1 则low=s+1;转步骤2。 3.3如果s>k-1,则high=s-1;转步骤2。 找第K大的数使用降序比较方便,而找第K小数使用升序。class Solution { public: int findKth(vector<int>a, int n, int K) { // write code here int low=0,high=n-1; int s=partition(a,low,high); while(1){ if(s==K-1) return a[s]; else if(s<K-1) { low=s+1; s=partition(a,s+1,high); } else { high=s-1; s=partition(a,low,s-1) } } } int partition(vector<int>&a,int low,int high) { int privot=a[low]; while(low<high){ while(low<high&&a[high]<=privot)high--; a[low]=a[high]; while(low<high&&a[low]>=privot)low++; a[high]=a[low]; } a[low]=privot; return low; } };
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
quickSort(a,0,n-1);
return a[n-K];//看清楚是第K大,不是第K小,我是从小到大排的数
}
//下面是快排经典代码
public void quickSort(int[] a,int start,int end){
if(start<end){
int i=partition(a,start,end);
quickSort(a,i+1,end);
quickSort(a,start,i-1);
}
}
public int partition(int[]a,int p,int q){//以数组第一个数为基准将数组分为左右两部分,左边小于基数,右边大于基数,然后把基数放在数组中合适的位置,返回该位置
int x=a[p];
int i=p;
for(int j=p+1;j<=q;j++){
if(a[j]<x){
swap(a,i+1,j);
i++;
}
}
swap(a,p,i);
return i;
}
public void swap(int[]a ,int i,int j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
Arrays.sort(a);
return a[n-K];
}
}
//使用快排,按照从大到小排序
int quickSortKth(vector<int> a, int start,int end, int K)
{
//划分
int left,right;
int pivot,temp;
left = start;
right = end-1;
pivot = a[left];
while (left < right){
while (left < right && a[right] <= pivot){
right --;
}
temp = a[left];
a[left] = a[right];
a[right] = temp;
while (left < right && a[left] >= pivot){
left ++;
}
temp = a[left];
a[left] = a[right];
a[right] = temp;
}
a[left] = pivot; //找到划分位置
if(K == left+1){
return a[left];
}else if(K < left+1){
return quickSortKth(a,start,left,K);
}else if(K > left+1){
return quickSortKth(a,left+1,end,K);
}
return -1;
}
int findKth(vector<int> a, int n, int K) {
return quickSortKth(a,0,n,K);
}
class Solution {
public:
int partition(vector<int> &nums, int begin, int end) {
int pivot = nums[begin];
int pivot_index = begin;
for(int i=begin+1; i!=end;i++){
if(nums[i] >= pivot){
pivot_index+=1;
if(pivot_index != i){
swap(nums[i], nums[pivot_index]);
}
}
}
swap(nums[begin], nums[pivot_index]);
return pivot_index;
}
int findKth(vector<int> &nums, int n, int k) {
return find_k(nums, 0, nums.size(), k);
}
int find_k(vector<int> &nums, int begin, int end, int k){
if( k<=0 || begin>end-1){
return -1;
}
int position = partition(nums, begin, end);
int left_length = position-begin;
if(left_length== k-1){
return nums[position];
}
else if(left_length > k-1){
return find_k(nums, begin, position, k);
}
else{
return find_k(nums, position+1, end, k-left_length-1);
}
}
};
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
return quickfind(a, 0, n-1, K);
}
int quickfind(vector<int>& a, int left, int right, int k) {
int i = left;
int j = right;
int mark = a[left];
while (i < j) {
while (i < j && a[j] >= mark)
--j;
if (i < j)
a[i++] = a[j];
while (i < j && a[i] <= mark)
++i;
if (i < j)
a[j--] = a[i];
}
a[i] = mark;
//哨兵右侧比他大的数字个数
int big_num = right - i;
//如果哨兵刚好是第K大的数
if (k - big_num - 1 == 0)
return mark;
else if (k - big_num - 1 > 0) {
//如果右侧数字个数不够K个,则从左侧找第k-big_num-1大的数
return quickfind(a, left, i - 1, k - big_num - 1);
} else {
//如果右侧数字个数比K多,则在右侧找第K大的数
return quickfind(a, i + 1, right, k);
}
}
};
核心思想:构建大小为K的小根堆。
时间复杂度:O(n * logK)
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
// 构建小根堆
for (int i = 0; i < K; i++) {
heapInsert(a, i);
}
for (int i = K; i < n; i++) {
if (a[i] >= a[0]) {
swap(a, 0, i);
heapify(a, 0, K);
}
}
return a[0];
}
public void heapInsert(int[] arr, int index) {
while (arr[index] < arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public void heapify(int[] arr, int index, int size) {
int left = 2 * index + 1;
while (left < size) {
int smallest = left + 1 < size && arr[left + 1] < arr[left] ?
left + 1 : left;
if (arr[smallest] < arr[index]) {
swap(arr, index, smallest);
} else {
break;
}
index = smallest;
left = 2 * index + 1;
}
}
public void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
function findKth( a , n , K ) {
return quickfind(a, 0, n - 1, K);
}
function quickfind(a, left, right, k) {
let i = left, j = right, pivot = a[left];
while (i < j) {
while (i < j && a[j] >= pivot) j--;
if (i < j) a[i++] = a[j];
while (i < j && a[i] <= pivot) i++;
if (i < j) a[j--] = a[i];
}
a[i] = pivot;
const deltaK = k - right + i - 1;
if (deltaK === 0) return pivot;
else if (deltaK > 0) return quickfind(a, left, i - 1, deltaK);
else return quickfind(a, i + 1, right, k);
} import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
Arrays.sort(a);
return a[n-K];
}
}