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()竟然過了,果然是我太菜了。

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