1. 程式人生 > >字尾陣列(基數排序)

字尾陣列(基數排序)

不理解字尾陣列的童鞋,可以看看挑戰程式設計書上講的,非常好,不過那上面講的使是用sort進行的排序,效率較基數排序低。不過思想一樣,那上面看懂了看這個很快。

說三點:

(1)y[]陣列表示按照第二關鍵字排號的情況,目前裡面存的時第一關鍵字的值,比如  y[1]=4,表示第二關鍵字排在第1位上此時第一關鍵字為下標從4開始的子字串。因此用基數排序,因為其相當穩定。

(2)swap交換後,計算x此時x就代表rank陣列,相當於rank[sa[i]]=i,因為存在相等的子串,所以要判斷一下。

(3)排好序的時候,因為沒有後綴再相同,所以此時p>=n

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000;
const int maxasc = 128; //ascII碼[0,127]
char s[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;

void debug()
{
    for(int i=0; i<n; i++) printf("%d ",sa[i]);
    printf("\n");
}

void build_sa(int m)
{
    int *x = t1, *y = t2;
    for(int i=0; i<m; i++) c[i] = 0;
    for(int i=0; i<n; i++) c[x[i] = s[i]]++;
    for(int i=1; i<m; i++) c[i] += c[i-1];
    for(int i=n-1; i>=0; i--) sa[--c[x[i]]] = i;
    cout<<"x[  ";
        for(int i=0;i<n;i++){
            cout<<x[i]<<"  ";
        }
        cout<<"  ]"<<endl;
    cout<<"sa[  ";
        for(int i=0;i<n;i++){
            cout<<sa[i]<<"  ";
        }
        cout<<"  ]"<<endl;
    for(int k=1; k<=n; k = k<<1)
    {
        int p = 0;

        for(int i=n-k; i<n; i++) y[p++] = i;

        for(int i=0; i<n; i++) if(sa[i] >= k) y[p++] = sa[i]-k;
        cout<<"y[  ";
        for(int i=0;i<n;i++){
            cout<<y[i]<<"  ";
        }
        cout<<"  ]"<<endl;
        for(int i=0; i<m; i++) c[i] = 0;
        for(int i=0; i<n; i++) c[x[y[i]]]++;
        for(int i=0; i<m; i++) c[i] += c[i-1];
        for(int i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];

        cout<<"sa[  ";
        for(int i=0;i<n;i++){
            cout<<sa[i]<<"  ";
        }
        cout<<"  ]"<<endl;

        swap(x,y);
        p = 1; x[sa[0]] = 0;

        for(int i=1; i<n; i++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k] ? p-1 : p++;

        cout<<"x[  ";
        for(int i=0;i<n;i++){
            cout<<x[i]<<"  ";
        }
        cout<<"  ]"<<endl;
        if(p >= n) break;
        m = p;
    }
}

int main()
{
    scanf("%s",s);
    n = strlen(s);
    build_sa(maxasc);
    return 0;
}

計蒜客的另外一份模板,沒有下面這個好理解,但先放著把,畢竟最好用。

#include <iostream>
#include <string.h>
using namespace std;

const int MAX_N=210000;
char s[MAX_N];
int sa[MAX_N],t[MAX_N],t2[MAX_N],c[MAX_N],n;

void build_sa(int m){
    int i,*x=t,*y=t2;
    for(i=0;i<m;i++) c[i]=0;
    for(i=0;i<n;i++) c[x[i]=s[i]]++;
    for(i=1;i<m;i++) c[i]+=c[i-1];
    for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(i=n-k;i<n;i++) y[p++]=i;
        for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[y[i]]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n) break;
        m=p;
    }
}

int Rank[MAX_N],h[MAX_N];
void get_h(){
	int i,j,k=0;
    for(i=0;i<n;i++) Rank[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k) k--;
        if(Rank[i]){
            j=sa[Rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            h[Rank[i]]=k;
        }
    }
}

int main() {
    cin>>s;
    n=strlen(s);
    build_sa(131);
    get_h();
    return 0;
}

單子符串問題:

兩個字串問題:

多個字串問題:

相關推薦

字尾陣列基數排序

不理解字尾陣列的童鞋,可以看看挑戰程式設計書上講的,非常好,不過那上面講的使是用sort進行的排序,效率較基數排序低。不過思想一樣,那上面看懂了看這個很快。 說三點: (1)y[]陣列表示按照第二關鍵字排號的情況,目前裡面存的時第一關鍵字的值,比如  y[1]=4,表示第

字尾陣列基數排序實現

基數排序(不懂基數排序的看這裡-->基數排序) 基數排序的時間複雜度是,總的時間複雜度是 C++程式碼實現: #include <bits/stdc++.h> using namespace std; #define infy 0x3f3f3f3f #

字尾陣列基數排序

字串裡算難了。。參考了好多部落格 推薦https://blog.csdn.net/YxuanwKeith/article/details/50636898   每個陣列的含義:sa[i]:排在第i位的子串的位置,、         rank[i]:位置 i 的子串排在第幾位        

合併兩個有序陣列歸併排序

package com.zyt.interview; public class MergeSortArray { public static int[] sort(int[] a,int[]

字尾陣列sort版

以下內容均取自挑戰程式設計競賽 目錄 4.應用 1.字尾陣列的計算: int n,k; int rankk[maxn+1]; int tmp[maxn+1]; //sa[i]表示排在第i的字串起始字母的下標。 //rank[i]表示從第i位字母開始的

內部排序演算法5基數排序

基數排序 多排序碼排序的概念 如果每個元素的排序碼都是由多個數據項組成的組項,則依據它進行排序時就需要利用多排序碼排序。實現多排序碼排序有兩種常用的方法,最高位優先(Most Significant Digit (MSD) First)和最低位優先(Le

排序下篇快速排序、並歸排序、堆排序、桶排序/基數排序

5.快速排序 (1)原理: 在要排序的一組數中,通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。 (2)圖解:這第一次迴圈5 小黑框是已確定位置,大黑框中使用遞迴 (3)程

【知識總結】字尾陣列Suffix_Array

又是一個學了n遍還沒學會的演算法…… 字尾陣列是一種常用的處理字串問題的資料結構,主要由\(sa\)和\(rank\)兩個陣列組成。以下給出一些定義: \(str\)表示處理的字串,長度為\(len\)。(下標從\(0\)開始) \([i,j)\)表示\(str\)從\(i\)到\(j - 1\)的字串

陣列選擇排序,氣泡排序

import java.util.Arrays; import javax.swing.text.StyledEditorKit.ForegroundAction; /* * 排序的兩種簡單演算法:選擇排序,氣泡排序 */ public class SequenceT

洛谷4248 AHOI2013差異 字尾陣列SA+單調棧

題目連結 補部落格! 首先我們觀察題目中給的那個求\(ans\)的方法,其實前兩項沒什麼用處,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); 那麼我們考慮剩下的部分應該怎麼求解! 首先這裡有一個性質。對於任意兩個字尾\(i,j\),他們的

字尾陣列uva10829

L-Gap Substrings If a string is in the form UVU, where Uis not empty, and V has exactly L characters, we say UVUis an L-Gap string. For

字尾陣列——hiho120最長可重疊重複K次子串

本人閱讀hihocoder題目及講解後整理此文章 題目分析 這個問題稱為“最長可重疊重複K次子串問題”,所求的是符合要求的所有子串的長度的最大值,這個要求是:子串在字串中重複出現過至少K次,其中子串可以(部分)重疊。 原文解題方法提示中

2406 Power Strings 字尾陣列dc3演算法模板

題目:給出一個字串 問它最多由多少相同的字串組成 。 kmp簡單的三十行程式碼而且時間還快,一切都是為了dc3模板 /* 複雜度接近O(n) 所有相關陣列都要開三倍 */ #include<iostream> #include<cstdio> #i

字尾陣列UVa11107

第一次寫字尾陣列啦啦啦。。。 對於字尾陣列的認知問題,我們還是看看大神 好,那下面我來提一提模板題UVa11107的解法: 題目大意:n個字串,求長度最大字串,要求在超過一半的字串中出現。 題解: 1、先在中間用分隔符把他們拼成一個長字串,求出他的字尾陣列和height

C# 陣列氣泡排序升序排序

 可用C#中中提供的專門排序的方法來降序,降序排序可以先Array.Sort() 再 Array.Reverse()。【先升序再反轉過來】降序排序可以先升序後再反轉排序 。陣列反轉排序: View Code C#中有提供專門排序的方法:System.Array.Reverse(要排序的陣列);//顛倒排序,反

一步一步寫演算法基數排序

【 宣告:版權所有,歡迎轉載,請勿用於商業用途。  聯絡信箱:feixiaoxing @163.com】     基數排序是另外一種比較有特色的排序方式,它是怎麼排序的呢?我們可以按照下面的一組數字做出說明:12、 104、 13、 7、 9     (1)按個位數排序是

找出陣列中第K個最小的數快速排序

問題描述:給定一個無序的陣列,從一個數組中找出第K個最小的數,例如,對於給定陣列序列{1,5,2,6,8,0,6},其中第4小的數為5。 演算法思路:採用快速排序,分而治之的思想,根據主元,每次Partiton以主元為軸,比它小的數在左邊,比它大的數在右邊,判

基數排序排序的C++實現

#include<iostream> #include<vector> #include<string> using namespace std; //低位優先 //測試資料   278 109 63 930 589 184 505 269 8 8

藍書演算法競賽進階指南刷題記錄——CH1402 字尾陣列二分+hash+快排

題目:CH1401. 題目大意:求出一個字串的所有後綴的排名,以及排名為i與i-1的字尾的最長公共字首LCP. 這道題一看是字尾陣列裸題,但是我不會 為了學習hash,我們考慮hash的寫法. 考慮SA的求法,顯然直接排序的串長是

九種經典排序演算法詳解氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序基數排序

綜述 最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬