快选和快排,都涉及到快速排序的思想。所以下面我们先介绍快速排序算法!
快速排序算法,时间复杂度为O(n log n),最坏的情况是O(n^2)。实现思想:选择一个基准元素,将数组分成两部分:比基准元素小的元素和比基准元素大的元素。然后,固定这个基准元素的位置,对这两部分分别递归地应用快速排序,直到整个序列有序
1. 选择基准元素,可以是第一个元素、最后一个元素、中间元素,或者随机选择。我是通常选择第一个,或者最后一个。下面以选择第一个为例子。
2. 设定两个指针,左指针指向数组的起始位置,右指针指向数组的结束位置,移动这两个指针,将数组分成两部分。下面是详细的分区方法:
使用两个指针,left 指向数组的起始位置,right 指向数组的末尾位置。
从右向左移动 right 指针,直到找到一个小于等于基准元素的元素。
从左向右移动 left 指针,直到找到一个大于等于基准元素的元素。
如果此时 left < right,则交换 nums[left] 和 nums[right]。
重复上述过程,直到 left >= right。最终 left 指针所在位置的元素与基准元素交换。
3. 递归排序,分别将左右两边的分别排序,直到完全排好。
#include <iostream>
#include <vector>
using namespace std;
// 快速排序函数
void quickSort(vector<int>& nums, int left, int right) {
if (left >= right) {
return;
}
// 选择基准元素,这里选择第一个元素作为基准
int pivot = nums[left];
int low = left;
int high = right;
// 开始分区操作
while (low < high) {
// 从右向左找到第一个小于基准元素的位置
while (low < high && nums[high] >= pivot) {
high--;
}
nums[low] = nums[high]; // 将小于基准元素的元素移到左边
// 从左向右找到第一个大于基准元素的位置
while (low < high && nums[low] <= pivot) {
low++;
}
nums[high] = nums[low]; // 将大于基准元素的元素移到右边
}
// 将基准元素放到正确的位置
nums[low] = pivot;
// 递归排序基准元素左边和右边的部分
quickSort(nums, left, low - 1);
quickSort(nums, low + 1, right);
}
// 示例用法
int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
cout << "排序前:";
for (int num : nums) {
cout << num << " ";
}
cout << endl;
quickSort(nums, 0, nums.size() - 1);
cout << "排序后:";
for (int num : nums) {
cout << num << " ";
}
cout << endl;
return 0;
本文主要详细介绍快速选择算法,快速选择算法的目标是找到未排序数组中第 k
大或第 k
小的元素,它通过分治的方式,在每次分区后只递归地处理包含目标元素的那一半数组。这使得它在平均情况下的时间复杂度为 O(n),最坏情况下为 O(n^2)。下面是代码。
#include <iostream>
#include <vector>
using namespace std;
// 快速选择函数
// 在数组 nums 中找到第 k 大的元素
int quickSelect(vector<int>& nums, int left, int right, int k) {
if (left == right) {
return nums[left];
}
// 选择基准元素,这里选择第一个元素作为基准
int pivot = nums[left];
int low = left;
int high = right;
// 分区操作
while (low < high) {
// 从右向左找到第一个大于基准元素的位置
while (low < high && nums[high] <= pivot) {
high--;
}
nums[low] = nums[high]; // 将大于基准元素的元素移到左边
// 从左向右找到第一个小于基准元素的位置
while (low < high && nums[low] >= pivot) {
low++;
}
nums[high] = nums[low]; // 将小于基准元素的元素移到右边
}
// 将基准元素放到正确的位置
nums[low] = pivot;
// 判断基准元素的位置与 k 的关系
if (k == low) {
return nums[low];
} else if (k < low) {
return quickSelect(nums, left, low - 1, k);
} else {
return quickSelect(nums, low + 1, right, k);
}
}
// 示例用法
int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
int k = 4; // 要找第 k 大的元素,这里示例 k = 4
cout << "数组:" << endl;
for (int num : nums) {
cout << num << " ";
}
cout << endl;
// nums.size() - k是寻找的第K大的值的下标;公式 K+index = nums.size()
int result = quickSelect(nums, 0, nums.size() - 1, nums.size() - k);
cout << "第 " << k << " 大的元素是:" << result << endl;
return 0;
}
最后是我自己写的快选,不知道为什么会超时?请大佬指点一下
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
if (k > nums.size() || k < 1) return 0;
return quicksort(nums, 0, nums.size() - 1, nums.size() - k); // 返回第 K 个大的值,nums.size() - k 为第 K 大的下标
}
private:
int partition(vector<int>& nums, int left, int right) {
int pivot = nums[right]; // 选择最右边的元素作为基准值
int i = left - 1; // 左指针,初始指向左边界的前一个位置
for (int j = left; j < right; ++j) {
if (nums[j] <= pivot) { // 将小于等于基准值的元素放到左侧
i++;
swap(nums[i], nums[j]);
}
}
swap(nums[i + 1], nums[right]); // 将基准值放到正确的位置
return i + 1; // 返回基准值的位置索引
}
int quicksort(vector<int>& nums, int low, int high, int k) {
if (low <= high) {
int q = partition(nums, low, high); // 分区操作
if (q == k) {
return nums[k];
} else if (q > k) {
return quicksort(nums, low, q - 1, k); // 左侧区间继续查找
} else {
return quicksort(nums, q + 1, high, k); // 右侧区间继续查找
}
}
return -1; // 处理边界情况,这里可以返回一个合适的默认值或者处理逻辑
}
};