手写快排模板
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l-1, j = r+1, x = q[(l+r)>>1];//先移动,再判断。因此i, j的初始位置分别位于l, r的两侧。
while(i < j) {
while (q[++i] < x);//不取等号,(若x为最大值,则i会一直++)防止数组越界
while (q[--j] > x);//先移动,再判断。防止不移动,在外面卡住
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j);//这里j有没有可能为r?(中枢是向下取整,故不可能)
quick_sort(q, j + 1, r);//这里j+1有没有可能为l?
}
模板中有以下几点需要注意:
- 分治算法最怕把n分成0和n,因为这样可能造成无限划分。
while (q[++i] < x);
中的条件不能带等号,如果带等号可能造成下标增加到r + 1
,导致数组越界。if (i < j)
条件中可以加上等号,因为i == j
时表示自己和自己交换,因此没有任何影响。- 这里一定要选择
j
作为枢轴元素。并且左边部分递归区间是[l, j]
,右边部分递归区间是[j + 1, r]
。如果选择i
作为枢轴元素的话算法是有问题的。因为最终q[i] >= x
,并不一定在左边部分区间。当然也可以稍作改动使得可以使用i - 1
作为分界点。 - 注意这里是先移动,再判断。因此
i, j
的初始位置分别位于l, r
的两侧。因为两个指针在每次交换完之后都需要向中间移动一位,因此我们可以每次上来就先移动一次,这样我们就需要把指针的初始值放到外侧。
使用 i 作为分界点的快排模板
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r + 1 >> 1];
while (i < j)
{
do i++; while (q[i] < x);
do j--; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, i - 1);
quick_sort(q, i, r);
}
LC347. 前 K 个高频元素
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
class Solution {
public:
vector<pair<int, int>> vec;
vector<int> ans;
void myqsort(int l, int r, int k) {
if(l >= r) {
if(l == k-1 && r == k-1) {
ans.push_back(vec[l].first);
}
return;
}
int i = l-1, j = r+1, mid = vec[(l+r)>>1].second;
while(i < j) {
while(vec[++i].second > mid);
while(vec[--j].second < mid);
if(i < j) swap(vec[i], vec[j]);
}
if(j <= k-1) {
for(int x = l; x <= j; ++x) {
ans.push_back(vec[x].first);
}
if(j < k-1) myqsort(j+1, r, k);
} else {
myqsort(l, j, k);
}
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> ump;
for(int a : nums) ump[a]++;
for(auto iter : ump) vec.push_back(iter);
//for(auto v : vec) cout << v.first << "-->" << v.second << endl;
myqsort(0, vec.size()-1, k);
return ans;
}
};