Leetcode刷题记录之排序算法
快速排序
快速排序的模板:
https://leetcode.cn/leetbook/read/illustration-of-algorithm/p57uhr/
215. 数组中的第K个最大元素
题目描述
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
输入输出
输入: [3,2,1,5,6,4], k = 2
输出: 5
题解
时间复杂度证明
这题使用快排时间复杂度为O(n),可以这样理解:
1、快排可以看成是二叉树,1分2,2分4......
2、每一层都是O(n)的,一共有logn层,故快排时间复杂度是O(nlogn)
3、这一题因为有个判断,可以每次快排时只对一边快排,故每一层的时间复杂度都是上一层的一半。
第一层n,第二层n/2,第三层n/4,共logn层。套用等比数列求和公式,可以得出O(n).
代码
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int left = 0, right = static_cast<int>(nums.size()) - 1;
int target = (static_cast<int>(nums.size()) - (k - 1)) - 1;
std::shuffle(nums.begin(), nums.end(), std::mt19937(std::random_device()()));
while (left < right) {
int mid = partition(nums, left, right);
if (mid == target) {
return nums[target];
} else if (mid < target) { // 去数组右半部分继续寻找
left = mid + 1;
} else { // 去数组左半部分继续寻找
right = mid - 1;
}
}
return nums[left];
}
int partition(vector<int> &nums, int left, int right) {
// 选择left作为划分的基数
int base = left;
int i = left, j = right;
while (i < j) {
while (i < j && nums[j] >= nums[base]) --j;
while (i < j && nums[i] <= nums[base]) ++i;
std::swap(nums[i], nums[j]);
}
std::swap(nums[i], nums[base]);
return i;
}
};
刷题记录
一刷 | 2022年8月11日 |
---|
剑指 Offer 40. 最小的k个数
题目描述
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
输入输出
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
题解
和 215 题一样,使用基于快速排序的快速选择,注意在选择之前先用 shuffle
打乱数组。
代码
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
int i = 0, j = static_cast<int>(arr.size()) - 1;
std::shuffle(arr.begin(), arr.end(), std::mt19937(std::random_device()()));
while (i <= j) {
int mid = partition(arr, i, j);
if (mid == k - 1) return vector<int>{arr.begin(), arr.begin() + k};
else if (mid < k - 1) i = mid + 1;
else j = mid - 1;
}
return {};
}
int partition(vector<int> &arr, int left, int right) {
int i = left, j = right;
while (i < j) {
while (i < j && arr[j] >= arr[left]) --j;
while (i < j && arr[i] <= arr[left]) ++i;
std::swap(arr[i], arr[j]);
}
std::swap(arr[i], arr[left]);
return i;
}
};
刷题记录
一刷 | 2022年8月12日 |
---|
桶排序
什么是桶排序
https://blog.csdn.net/sinat_31275315/article/details/107868240
347. 前 K 个高频元素
题目描述
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
输入输出
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
题解
利用桶排序的思想:
-
遍历字符串,统计每个整数出现的频率,同时记录最高频率
max_frequency
; -
创建桶,以整数出现的频率作为数组的下标,每个桶中存放相同出现频率的整数集合;
-
按照出现频率从大到小的顺序遍历桶,对于每个出现频率,获得对应的整数。

代码
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
// [key, value] = [num, num出现的频率]
unordered_map<int, int> frequency;
// 最高的出现频率,作为桶的长度
int max_frequency = 0;
for (const auto &item: nums) {
max_frequency = std::max(max_frequency, ++frequency[item]);
}
// 使用vector作为桶
// buckets[频率] = [num1, num2, ....] 把频率相同的元素放入同一个桶内
vector<vector<int>> buckets(max_frequency + 1);
for (const auto &item: frequency) {
buckets[item.second].push_back(item.first);
}
vector<int> result(k);
int j = 0;
// 从后往前遍历桶,将桶内元素加到result数组中
for (int i = static_cast<int>(buckets.size()) - 1; i >= 0; --i) {
for (const auto &num : buckets[i]) {
if (j >= k) return result;
result[j++] = num;
}
}
return result;
}
};
刷题记录
一刷 | 2022年8月13日 |
---|
451. 根据字符出现频率排序
题目描述
给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
返回 已排序的字符串 。如果有多个答案,返回其中任何一个。
输入输出
输入: s = "tree"
输出: "eert"
解释: 'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。
题解
和 347 题一样,利用桶排序的思想,只不过这次是将整数换成了字符。
代码
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> frequency_map;
int max_frequency{};
for (const auto &item: s) {
max_frequency = std::max(max_frequency, ++frequency_map[item]);
}
// buckets[字符出现的频率] = [a, b, ...]
vector<vector<char>> buckets(max_frequency + 1);
for (auto &[c, frequency] : frequency_map) {
buckets[frequency].push_back(c);
}
int idx = 0;
// 从后往前遍历桶中的元素,构造返回值
for (int i = static_cast<int>(buckets.size()) - 1; i > 0; --i) {
for (int j = 0; j < buckets[i].size(); ++j) {
for (int k = 0; k < i; ++k) {
if (idx >= s.size()) return s;
s[idx++] = buckets[i][j];
}
}
}
return s;
}
};
刷题记录
一刷 | 2022年8月13日 |
---|