1.题目:牛客网 NC88 (寻找第K大)
描述
有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(1<K<n),请返回第k大的数(包括重复的元素,不用去重),保证答案存在。
要求时间复杂度O(n)
示例1
输入:
[1,3,5,2,2],5,3
返回值:
2
2.解题思路
这题给了提示,可以借用快排的思想。同时要注意对事件复杂度的要求是O(n)。
对于快排不熟悉的,建议看下我的这篇博文:快速排序详细讲解和代码实现
先给大家介绍第一种思路:先对A进行快速排序(从小到大),然后返回第K大的数
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
quickSort(a,0,n-1);
return a[n-K];
}
void quickSort(vector<int> &A,int low,int high)
{
if(low<high)
{
int pivotpos=Partition(A,low,high);
quickSort(A,low,pivotpos-1);
quickSort(A,pivotpos+1,high);
}
}
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;
}
};
这里自己实现了快速排序算法,在排序时,调用了快排。时间复杂度O(nlogn)
因题目要求是O(n),所以必须对代码做优化。
显而易见,上述解法没有充分利用有效信息。题目中只要求返回第k大的值,并没有要求要对整个数组排序。
在这里有优化的地方。
在快排中,我们只要一趟快排,就使得这趟快排基准privot的位置得以确定。下一趟快排,使得重新确定的基准的位置又得以确定。
因此,每一趟快排后,比如急转的位置为pivotpos,就比较pivotpos和n-K的关系(从小到大的快排):
1.pivotpos=n-K,找到该元素。此元素就是数组A中第k大的数。
2.pivotpos<n-K,往右边的划分继续寻找quickSort(A,pivotpos+1,high)。
3.pivotpos>n-K,往左边的划分继续寻找quickSort(A,low,pivotpos-1)。
代码实现:
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
return quickSort(a,0,n-1,K,n);
//return a[n-K];
}
int quickSort(vector<int> &A,int low,int high,int k,int n)
{
if(1)
{
int pivotpos=Partition(A,low,high);
if(pivotpos==k)
return A[n-pivotpos];
else if(pivotpos<k)
return quickSort(A,pivotpos+1,high,k,n);
else
return quickSort(A,low,pivotpos-1,k,n);
}
//return -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;
}
};
这样改写后,时间复杂度满足了要求,但使用到了递归,测试用例只通过过了几组。可能未通过的测试用例中,A相对大,超出了递归栈的深度。有可能代码有点问题。读者觉得呢?
继续改写,不使用递归
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
return quickSort(a,0,n-1,K,n);
//return a[n-K];
}
int quickSort(vector<int> &A,int low,int high,int k,int n)
{
while(1)
{
int pivotpos=Partition(A,low,high);
if(pivotpos==n-k)
return A[pivotpos];
else if(pivotpos<n-k)
//return quickSort(A,pivotpos+1,high,k,n);
low=pivotpos+1;
else
//return quickSort(A,low,pivotpos-1,k,n);
high=pivotpos-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;
}
};
读者有什么想法,可留言评论。