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

基数排序

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

51nod3084:猪猪侠的字符串

题意很简单, n n 个长度为 k k 的字符串,输出按字典序排序后的结果,其中 n k 5 1 0 6 nk\le5*10^6

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

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

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

看到数据, n k 5 1 0 6 nk\le5*10^6 ,盲猜正解应该是 O ( n k ) O(nk) 的算法,最多加个 l o g n logn ,但有什么算法是和字符串长度有关的呢?

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

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

、

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

对于这道题,只需要把上面gif的0~9改为a~z,然后对于每一个字符串从后往前排 k k 趟序就好了,时空复杂度 O ( n k ) 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.

发布了7 篇原创文章 · 获赞 10 · 访问量 436

猜你喜欢

转载自blog.csdn.net/weixin_44700995/article/details/105190964