排序
快排
第k个最小值
class Solution {
public:
vector<int> smallestK(vector<int>& arr, int k) {
vector<int> result;
if (k <= 0 || arr.empty())
return result; // 处理边界情况
quicksort(arr, 0, arr.size() - 1, k);
result.assign(arr.begin(), arr.begin() + k); // 复制前k个元素到结果
return result;
}
void quicksort(vector<int>& arr, int l, int r, int k) {
if (l < r) { // 确保左指针小于右指针
int pos = partition(arr, l, r); // 获取分区位置
if (pos == k - 1) { // 如果分区位置正好是第K小的位置
// 已经找到第K小的元素,不需要进一步排序
return;
} else if (pos > k - 1) {
// 如果第K小的元素在左分区,则递归左分区
quicksort(arr, l, pos - 1, k);
} else {
// 否则,递归右分区
quicksort(arr, pos + 1, r, k);
}
}
}
// 分区
int partition(vector<int>& nums, int low, int high) {
// 以第1位元素为基准数
int pivot = nums[low];
int i = low, j = high;
while (i < j) {
// 从右向左找到第1个小于基准数的元素
while (i < j && nums[j] >= pivot) {
j--;
}
// 从左向右找到第1个大于基准数的元素
while (i < j && nums[i] <= pivot) {
i++;
}
// 交换元素
swap(nums[i], nums[j]);
}
// 将基准数放到正确位置上
swap(nums[j], nums[low]);
return j; // 返回基准元素的索引位置
}
};
要点:
①分区函数返回基准值位置,根据分区位置与k的关系,判断是否再进行递归
②分区时,采用双指针的方法;将基准放到正确位置上,要注意;如果是以第一个元素作为基准数,那么一定是先从右到左找小于基准数的元素。(如果先从左到右,会出错,即把大数换到了第一位)
滑动窗口
最大连续1的个数
法一:前缀和
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int n = nums.size();
int left = 0, lsum = 0, rsum = 0;
int ans = 0;
for (int right = 0; right < n; ++right) {
rsum += 1 - nums[right];
while (lsum < rsum - k) {
lsum += 1 - nums[left];
++left;
}
ans = max(ans, right - left + 1);
}
return ans;
}
};
要点:
①使用双指针滑动窗口。因为只有0和1,分别计算两个指针的前缀和,即可得到1的个数。(想得到零的个数,即 前缀和 += 1-nums[i] );
②使得两个前缀和(0的个数)之差小于等于k即可满足要求。
③右指针遍历,得到右指针前缀和,循环判断左指针前缀和是否满足要求,不满足,左指针前缀和++,左指针++;比较 ans和(r-l+1); 注意:判断满足要求的是 right 和 left-1指针的前缀和之差。所以先前缀和+=,再左指针++。
法二:记录零的个数
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int ans = 0;
int zero_count = 0;
int l=0;
int r=0;
while(r<nums.size()){
if(!nums[r]){
zero_count++;
}
if(zero_count>k){
if(!nums[l]){
zero_count--;
}
l++;
}
ans = max(ans,r-l+1);
r++;
}
return ans;
}
};
要点:
①每次都要判断,计数是否大于k,使左指针移动到满足条件的位置。
②先选择ans,再r++。否则会导致结果+1。