基数排序
怎么说呢,其实这已经是上学期DS&A学过的了,但是当时没怎么看,以为std::sort()天下第一,其他排序算法都没啥用武之地,直到昨天看到了这道题:
题意很简单, 个长度为 的字符串,输出按字典序排序后的结果,其中 。
第一反应:这不是字典树sb题吗?
刚打开模板,突然发现不太对劲, ,这谁顶得住啊…
既然空间上不行,就要换一个可行的算法了。
看到数据, ,盲猜正解应该是 的算法,最多加个 ,但有什么算法是和字符串长度有关的呢?
长度…排序…对了,好像上学期学过一个排序算法…基数排序!
那么什么是基数排序呢,我先去菜鸟教程偷个图:
简而言之,基数排序利用了数据不同位置的不同权重对顺序的影响(比如,对于字符串 , 的大小对 不同的字符串顺序并无影响)来保证对每趟排序后的数据局部有序,全部排序后的数据整体有序。
对于这道题,只需要把上面gif的0~9改为a~z,然后对于每一个字符串从后往前排 趟序就好了,时空复杂度 。
AC代码:
有一说一,5e6个字符用cin竟然没TLE
#include <bits/stdc++.h>
#define N 5000010
using namespace std;
int n,order[N];//order为排序后字符串的下标
queue<int> q[26];//表示26个字母作为基数
string s[N];
void redix_sort(int a[],int len,int n)//基数排序O(nlen)
{
for(int k=len-1;~k;k--)
{
for(int i=1;i<=n;i++)
q[s[a[i]][k]-'a'].push(a[i]);
for(int i=0,j=0;j<26;j++)
while(q[j].size())
{
a[++i]=q[j].front();
q[j].pop();
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
order[i]=i;//字符串初始顺序
}
redix_sort(order,s[1].size(),n);//对order而不是s排序避免了字符串复制的时间
for(int i=1;i<=n;i++)
cout<<s[order[i]]<<"\n";
}
今天比较短,毕竟有课要早点睡x
2020.3.30 4:28 a.m.