上篇文章:LeetCode模拟算法精解II:外观数列与数青蛙
目录
1.颜色分类
https://leetcode.cn/problems/sort-colors/description/


理解题意
对整数0,1,2进行原地排序,不能使用库内置sort函数,使数组升序。
算法原理
由于需要对三个对象同时排序,所以我们使用分治的思想,如下:

在[0, left]中:全为0
在[left+1, i - 1]中:全为1
在[i, right - 1]中:全为等待扫描的元素
在[right, n - 1]中:全为2
nums[i]为0时,交换left和i中的元素,并且left++,i++,不过需要区分先后。
nums[i]为1时,i++即可。
nums[i]为2时,交换right和i中的元素,right--,但是i不能动,因为i存储被交换的元素,暂时还不知道其元素的内容是什么。
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size();
for(int left = -1, i = 0, right = n; i < right;)
{
if(nums[i] == 0) swap(nums[++left], nums[i++]);
else if(nums[i] == 1) i++;
else swap(nums[--right], nums[i]);
}
}
};
2.排序数组
https://leetcode.cn/problems/sort-an-array/description/


理解题意
在时间复杂度为o(nlog(N))的前提下,不使用内置函数,将数组变为升序排列。
算法原理
在上一题"颜色分类"中,运用了分类和快速排序的方式,在本题中,则需要在此基础上进行优化--由于时间复杂度的要求。
注意:如果想要时间复杂度接近nlog(n),那么基准元素的取值就应该是取随机值,此结论在算法导论中有所提及。
我们先随机选取一个基准元素key,在此基础上,对数组中的元素进行分类:

此后,如果nums[i] < key:swap(nums[++left], nums[i++])
如果nums[i] = key:i++
如果nums[i] > key:swap(nums[--right], nums[i])
而有关基准元素的选择,我们使用:r = rand();
接着,取其下标:nums[r % (left - right + 1) + left],其中,r % (left - right + 1)表示为[0, n - 1]
代码如下:
class Solution
{
public:
vector<int> sortArray(vector<int>& nums)
{
srand(time(NULL));
qsort(nums, 0, nums.size() - 1);
return nums;
}
void qsort(vector<int>& nums, int l, int r)
{
if(l >= r) return;
// 数组分三块
int key = getRandom(nums, l, r);
int i = l, left = l - 1, right = r + 1;
while(i < right)
{
if(nums[i] < key) swap(nums[++left], nums[i++]);
else if(nums[i] == key) i++;
else swap(nums[--right], nums[i]);
}
// [l, left] [left + 1, right - 1], [right, r]
qsort(nums, l, left);
qsort(nums, right, r);
}
int getRandom(vector<int>& nums, int left, int right)
{
int r = rand();
return nums[r % (right - left + 1) + left];
}
};
本章完。