Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4]
and k = 2, return 5.
Note:
You may assume k is always valid, 1 ≤ k ≤ array's length.
这是一道分治的经典题目,不通过排序将第k大的数字找出来。
基本思路:随机选定一个pivot,从而将数组分成三部分,分别是A小于pivot,B等于pivot和C大于pivot的部分。然后通过比较k与三个部分的长度,可以减少搜索的范围。通过不断减少搜索范围直到找到第k个数。
具体规则:1.k<=A.size,就变成在A中寻找第k大数
2.k>A.size && k <= A.size+B.size, 那么当前的pivot就是第k大数
3.剩下的情况是第k大数出现在C中,就变成在C中寻找第k-A.size+B.size大的数
主要的思路不难,选择这道题主要是为了尝试实现不通过另外申请空间,原地将数组分成三个部分。
我的实现思路是:1.用less指针指着数组头部,用more指针指着数组尾部,equal指针初始化为n。(下标为0到n-1)
2.如果less<=more,检查less指针的元素l,否则结束
2.1如果l小于选定的pivot,那么less+1往右移一格,再次进行2;
2.2如果l大于等于选定的pivot,则无论more指着什么,都将l与more指着的元素交换,然后进行3
3.检查交换过来的元素l:
3.1如果l大于pivot,那么more-1往左移一格,再次进行2;
3.2如果l等于pivot,那么将l与(equal-1)指着的元素进行交换,然后equal-1往左移动,more-1往左移动,再次进行2
以下是AC的代码
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size();
k = n-k+1; // 将求第k大转为求第k'小
int less = 0;
int more = n-1;
int equal = n;
int sl, sr, sv,v, start, end;
while (1) {
start = less; //记下每次搜索数组的起始和结束位置
end = more;
n = equal;
v = nums[less]; // pivot
if (start == end) return v;
while (less != more) {
if (nums[less] < v) {
less++;
} else {
if (less != more)
swap(nums[less],nums[more]);
if (nums[more] > v) {
more--;
} else {
equal--;
if (equal != more)
swap(nums[equal],nums[more]);
more--;
}
}
}
sv = n-equal;
sl = nums[less] < v ? less-start+1 : less-start;
sr = nums[less] < v ? equal-more-1 : equal-more;
if (k <= sl+sv && k >sl) {
return v;
} else if (k <= sl) {
less = start;
more = (nums[more] >= v) ? more-1:more;
equal = more+1;
} else {
k = k-sl-sv;
less = (nums[more] < v) ? less+1:less;
more = equal-1;
}
}
return -1;
}