这是一道来自LintCode的题目,题目原文是这样的:
LeetCode对应的题号是215。
我的做法:
class Solution {
public:
/**
* @param n: An integer
* @param nums: An array
* @return: the Kth largest element
*/
int kthLargestElement(int n, vector<int> &nums) {
int tmp=0;
tmp = partition(nums, 0, nums.size()-1, nums.size() - n);
for (int i = nums.size()-1; i >= 0; i--){
cout << nums[i] << endl;
}
return tmp;
}
private:
int partition(vector<int> &nums, int start, int end, int k) {
// 一定要有这个,不然就一直递归下去了
if (start >= end) {
return nums[k];
}
int left = start;
int right = end;
int pivot = nums[(start + end) / 2];
while(left<=right){
while (nums[left]<pivot && left <= right)left++;
while (nums[right]>pivot && left <= right)right--;
if(left<=right){
// 其实用C++自带的swap也行,但是运行速度会慢一点
swap(nums, left, right);
left++;
right--;
}
}
partition(nums, start, right, k);
partition(nums, left, end, k);
return nums[k];
}
void swap(vector<int> &nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
};
其实核心思想就是快排,这里粗略讲一下思路:
- 选取基准数字
其实选取基准数字的方法不固定,我这里是选择了数组中间的数字作为基准(省事一点)。
- 开始比较
例子来自坐在马桶上看算法:快速排序,此处略有改动。例如数组是6 1 2 7 9 3 4 5 10 8
,
我们从两端开始探测:
那两个小人就是当前在操作的数字,首先左边的小人会向右走,同时将自己脚下面的数字和基准数字进行比较,因为我们排列的目的是让数字升序排列,即最终结果为1 2 3 ... 10
,所以左侧小人探测的目标是比基准数字大的数字。左侧小人找到目标并停下后,右侧小人会开始向左走,探测目标是比基准数字小的数字。两个小人都是一旦发现了目标就在目标上方停下。两个小人都找到自己对应的目标之后就会进行交换。
如此类推,直到两个小人碰在了一起:
这时候就应该将数组分割成两部分,然后在每个部分中单独重复上述步骤。
注意我的程序中的判断条件,我的目的是在碰面之后再让左右的“小人”继续走一步,然后直接依据两个小人的位置将数组进行分割。