字尾陣列(基數排序)
不理解字尾陣列的童鞋,可以看看挑戰程式設計書上講的,非常好,不過那上面講的使是用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種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬