在未排序的数组中找到第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
排序算法:快速排序(详情可参考《数据结构》严蔚敏版本)
一次快速排序代码实现:
递归调用实现快速排序:
方法一(严蔚敏方法):
①设定两个指针,low和high。
②当右边的数字大于pivot的值,high指针一直减减,直到遇到小于pivot的值。交换low和high的值
③移动low指针,当左边的数字小于pivot的时候,low指针一直加加,直到遇到大于pivot的值。交换low和high的值
④重复2,3步骤,知道low=high
实现了从小到大的排列
代码实现:
public static int partition(int[] nums,int low,int high) {
int pivotKey=nums[low];//枢轴记录关键字
while(low<high) {
while(low<high&&nums[high]>=pivotKey) {
high--;
}
nums[low]=nums[high];
while(low<high&&nums[low]<=pivotKey) {
low++;
}
nums[high]=nums[low];
}
nums[low]=pivotKey;
return low;//枢轴记录到位
}
方法二:
①设置左右两个指针,right与left,指向数组的头和尾
②当满足左指针的数大于pivot并且右指针的数小于pivot,两个值互换
③如果左指针的数小于pivot,左指针加加 (执行一次)
④如果右指针的数大于piovot,右指针减减 (执行一次)
⑤重复2,3,4步骤
实现了从小到大的排列
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[left], l = left + 1, r = right;
while (l <= r) {
if (nums[l] > pivot && nums[r] < pivot) {
swap(nums[l++], nums[r--]);
}
if (nums[l] <= pivot) ++l;
if (nums[r] >= pivot) --r;
}
swap(nums[left], nums[r]);
return r;
};
方法一与方法二的区别是:方法一中,某一侧的指针一直移动,直到不满足条件,跳到另一侧指针,此时另一侧指针一直移动,直到不满足条件;在方法二中,每次循环,两侧的指针都移动,相当于共同逼近中点
这道题最好的解法应该是下面这种做法,用到了快速排序Quick Sort的思想,因为是求第k个最大数,所以这里排序的方向是从大往小排。
就把大于中枢点的数字放到左半边,把小于中枢点的放在右半边,这样中枢点是整个数组中第几大的数字就确定了,虽然左右两部分不一定是完全有序的,但是并不影响本题要求的结果,所以我们求出中枢点的位置,如果正好是k-1,那么直接返回该位置上的数字;如果大于k-1,说明要求的数字在左半部分,更新右边界,再求新的中枢点位置;反之则更新右半部分,求中枢点的位置;
代码实现
方法一:
public static int partition(int[] nums,int low,int high) {
int pivotKey=nums[low];//枢轴记录关键字
while(low<high) {
while(low<high&&nums[high]<=pivotKey) {
high--;
}
nums[low]=nums[high];
while(low<high&&nums[low]>=pivotKey) {
low++;
}
nums[high]=nums[low];
}
nums[low]=pivotKey;
return low;//枢轴记录到位
}
public int findKthLargest(int[] nums, int k) {
int low=0,high=nums.length-1;
while(true) {
int pos=partition(nums, low, high);
if(pos==k-1) return pos;
else if(pos>k-1) high=pos-1;
else low=pos+1;
}
}
方法二:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int left = 0, right = nums.size() - 1;
while (true) {
int pos = partition(nums, left, right);
if (pos == k - 1) return nums[pos];
else if (pos > k - 1) right = pos - 1;
else left = pos + 1;
}
}
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[left], l = left + 1, r = right;
while (l <= r) {
if (nums[l] < pivot && nums[r] > pivot) {
swap(nums[l++], nums[r--]);
}
if (nums[l] >= pivot) ++l;
if (nums[r] <= pivot) --r;
}
swap(nums[left], nums[r]);
return r;
}
};