相比朴素版计数排序,可以保证排序后数组中相等元素原本的先后顺序不变。
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
//1.得到数列的最大值和最小值,并算出差值d
int minVal = INT_MAX, maxVal = INT_MIN;
for (int i=0; i<n; i++) {
minVal = min(minVal, nums[i]);
maxVal = max(maxVal, nums[i]);
}
//2.创建统计数组并统计对应元素个数
int m = maxVal - minVal + 1;
vector<int> temp(m);
for (int i=0; i<n; i++) {
temp[nums[i]-minVal]++;
}
//3.统计数组做变形,后面的元素等于前面的元素之和
int sum = 0;
for (int i=0; i<m; i++) {
sum += temp[i];
temp[i] = sum;
}
//4.倒序遍历原数列,从统计数组找到正确位置,输出到结果数组
vector<int> ans(n, 0);
for (int i=n-1, j=0; i>=0; i--) {
ans[temp[nums[i]-minVal]-1] = nums[i];
temp[nums[i]-minVal]--;
}
return ans;
}
};
时间复杂度 O(n + k),n为元素个数,k 为元素的取值范围。
空间复杂度 O(k),不考虑结果数组分配空间。
计数排序的局限性:
-
当数列最大最小值差距过大时,并不适用计数排序。
比如给定20个随机整数,范围在0到1亿之间,这时候如果使用计数排序,需要创建长度1亿的数组。不但严重浪费空间,而且时间复杂度也随之升高。 -
当数列元素不是整数,并不适用计数排序。
如果数列中的元素都是小数,比如25.213,或是0.00000001这样子,则无法创建对应的统计数组。这样显然无法进行计数排序。