前言
今天刷leetcode的第164题直接就蒙了,后来看了题解才发现是桶排序的东西,咱们这回把这俩排序算法一起搞定,顺便把leetcode上的相关题目ac掉。
桶排序
其实桶排序非常好理解,就是将长的序列先分成等间距的很多个桶,然后将序列元素放进各自对应的桶里,最后桶内排序,就完了。这个过程实在是太过于简单,咱们就直接上代码。
leetcode164
题目描述
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
说明:
你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。
请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。
解题思路
其实桶排序就是决定一个桶的个数即可。我看网上的做法一般都是在数据量不大的情况下平均一个桶里存放一个数据,确实有点奢侈哈,当然你也可以自己看着来,要是数据量很大了,那就别吝啬桶的个数了。
代码
class Solution {
public:
int maximumGap(vector<int>& nums) {
if(nums.size() < 2)
return 0;
if(nums.size() < 500)
{
sort(nums.begin(), nums.end());
int res = nums[1] - nums[0];
for(int i = 0; i < nums.size()-1; ++ i)
res = (res > nums[i+1] - nums[i]) ? res : (nums[i+1] - nums[i]);
return res;
}
int maxVal = *max_element(nums.begin(), nums.end());
int minVal = *min_element(nums.begin(), nums.end());
int bucketNum = (maxVal - minVal) / nums.size() + 1;
int bucketSize = (maxVal - minVal) / bucketNum + 1;
list<int> temp;
vector<list<int>> details(bucketNum, temp);
for(int i = 0; i < nums.size(); ++ i)
{
int index = (nums[i] - minVal) / bucketSize;
if(details[index].empty() == true || nums[i] >= details[index].back())
details[index].push_back(nums[i]);
else
{
for(auto iter = details[index].begin(); iter != details[index].end(); ++ iter)
{
if(nums[i] < *iter)
{
details[index].insert(iter, nums[i]);
break;
}
}
}
}
bool hasReg = false;
int reg = 0;
int res = -1;
for(int i = 0; i < details.size(); ++ i)
{
if(details[i].empty() == false)
{
for(auto iter = details[i].begin(); iter != details[i].end(); ++iter)
{
if(hasReg == true)
{
res = (res == -1 || res < *iter - reg) ? (*iter - reg) : res;
reg = *iter;
}
else
{
hasReg = true;
reg = *iter;
}
}
}
}
return res;
}
};
看来桶排序确实没啥好说的。
快速排序
这个也非常基础了,这个我在TopK里应该是说过类似的东西。本质上就是选取一个基准,然后不停的交换,再交换,完成一部分后就继续寻找下一部分。TopK其实就是大差不差的快速排序,只不过不需要对所有的部分都排序。
leetcode 75
题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?
解题思路
代码实现
class Solution {
public:
void sortColors(vector<int> &nums) {
int size = nums.size();
if (size < 2) {
return;
}
// all in [0, zero) = 0
// all in [zero, i) = 1
// all in [two, len - 1] = 2
int zero = 0;
int two = size;
int i = 0;
while (i < two) {
if (nums[i] == 0) {
swap(nums[zero], nums[i]);
zero++;
i++;
} else if (nums[i] == 1) {
i++;
} else {
two--;
swap(nums[i], nums[two]);
}
}
}
};