Hile每日算法-3.30-基数排序

基数排序

怎么说呢,其实这已经是上学期DS&A学过的了,但是当时没怎么看,以为std::sort()天下第一,其他排序算法都没啥用武之地,直到昨天看到了这道题:

51nod3084:猪猪侠的字符串

题意很简单,nn个长度为kk的字符串,输出按字典序排序后的结果,其中nk5106nk\le5*10^6

第一反应:这不是字典树sb题吗?

刚打开模板,突然发现不太对劲,265106=1.310826*5*10^6=1.3*10^8,这谁顶得住啊…

既然空间上不行,就要换一个可行的算法了。

看到数据,nk5106nk\le5*10^6,盲猜正解应该是O(nk)O(nk)的算法,最多加个lognlogn,但有什么算法是和字符串长度有关的呢?

长度…排序…对了,好像上学期学过一个排序算法…基数排序

那么什么是基数排序呢,我先去菜鸟教程偷个图:

、

简而言之,基数排序利用了数据不同位置的不同权重对顺序的影响(比如,对于字符串sss[i]s[i]的大小对s[i1]s[i-1]不同的字符串顺序并无影响)来保证对每趟排序后的数据局部有序,全部排序后的数据整体有序。

对于这道题,只需要把上面gif的0~9改为a~z,然后对于每一个字符串从后往前排kk趟序就好了,时空复杂度O(nk)O(nk)

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.

21:24 updated:试了一遍,直接sort()竟然过了,果然是我太菜了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章