日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ 字符串数组长度排序_数组 | 后缀数组的求法及应用

發布時間:2024/10/12 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ 字符串数组长度排序_数组 | 后缀数组的求法及应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:Andy__lee

鏈接:https://blog.nowcoder.net/n/6b4a93e186ed4a358321de6a7c3b4f19

來源:??途W

定義

維基百科 - 后綴數組

讓我們來看一下 wiki 上的定義:

在計算機科學里, 后綴數組(英語:suffix array)是一個通過對字符串的所有后綴經過排序后得到的數組。此數據結構被運用于全文索引、數據壓縮算法、以及生物信息學。

令字符串

表示 的子字符串,下標從 到 。

的后綴數組 被定義為一個數組,內容是 的所有后綴經過字典排序后的起始下標。

滿足

。

求法

大體思想

這玩意可以使用倍增來求,當然也有常數比較大的

算法。

中心思想就是假設我們求出了考慮每個后綴前

個的字典序,現在我們需要擴展到 的情形。首先 的時候十分簡單,就是對應的 ASCII 碼??紤]每次 ,相當于要把每個后綴當做一個二元組來排序。我們考慮對于每個后綴指定兩個變量 和 ,目前考慮的長度下, 指這個后綴的排名, 指這個后綴后 個字母的排名。顯然 可以由上一輪的 得到(后面會單獨說)。然后我們就可以用上一輪的 和 當做二元組來排序,就能更新出這次的 了。

相信大家看完后肯定是一臉 mb,接下來我來詳細的說一下算法過程。

算法過程

首先我們來定義一些變量:

表示排名為 的后綴的位置, 表示第 個后綴的排名, 表示每次倍增里的第二關鍵字排名為 的位置,我們設這個字符串 的長度為 。

首先按照定義,顯然有

也就是說明了這兩個數組可以互相

推。

開始時

我們拿來排序的二元組是 來排序,顯然 ASCII 碼小的會在前面,相同的靠前的會在前面。然后我們開始倍增。考慮已經求出了長度為 的答案,考慮去更新 的答案。

現在我們考慮如何求出

(第二關鍵字)。代碼如下:p = 0; FOR(i,1,w) tp[++p] = N-w+i; FOR(i,1,N) if(sa[i] > w) tp[++p] = sa[i]-w;

首先對于長度

的后綴,一定字典序會在前面,我們先都拿出來。

然后對于長度

的后綴,我們發現后綴 的后 個字符就是上一輪后綴 的前 個字符。(考慮這一輪 個字符的意義下)

所以代碼就是按照上一輪的順序從小到大枚舉了每個長度

的后綴,然后找到第二關鍵字的對應位置定位過去即可。

之后我們搞個比較高效的排序(基數排序)排一下。

然后因為在這個倍增過程中可能有的后綴的

暫時相同,但是最后的答案一定是互不相同,于是我們需要對于這一輪的結果去一下重(重新分配 編號)std::swap(tp,rk); // rk 沒用了,當然這里最好寫指針交換 rk[sa[1]] = p = 1; FOR(i,2,N) rk[sa[i]] = (tp[sa[i-1]] == tp[sa[i]] && tp[sa[i-1]+w] == tp[sa[i]+w]) ? p : ++p;

去重的原理和上面的類似:如果前半段和后半段在上一輪的rkrk相同的話那它們當前就是相同的。

然后就做完了。。。。

現在我們要解決的是找到一種高效的排序方法,首先顯然你不能用

排序,要不然和暴力就沒區別了(可能還更慢)。

所以我們考慮

的基數排序。

先放一下代碼:

inline void sort(){FOR(i,0,M) tax[i] = 0;FOR(i,1,N) tax[rk[i]]++;FOR(i,1,M) tax[i] += tax[i-1];ROF(i,N,1) sa[tax[rk[tp[i]]]--] = tp[i]; }

首先我們把桶清空,然后統計每種

的出現次數,然后做個前綴和(有助于快速查詢排名)。

然后我們重點關注最后一句是在干什么。首先我們按第二關鍵字從大到小枚舉(

),然后我們在找一下當前枚舉的這個后綴的第一關鍵字排名( ??),然后由于是第二關鍵字從大到小枚舉,所以目前的字符串排名一定是前半段相同的后綴中(當前 相同)最靠后的一個后綴,所以我們的前綴和就派上用場了。最后直接更新一下就可以了(排名是 的后綴是 號后綴)。

是不是很好理解?這樣后綴數組就寫完了。

附上Luogu - 后綴排序的代碼:

#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdio> #include <vector> #include <cstdlib> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <map> #include <set>#define Re register #define LL long long #define U unsigned #define FOR(i,a,b) for(Re int i = a;i <= b;++i) #define ROF(i,a,b) for(Re int i = a;i >= b;--i) #define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c) #define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c) #define CLR(i,a) memset(i,a,sizeof(i)) #define BR printf("--------------------n") #define DEBUG(x) std::cerr << #x << '=' << x << std::endlconst int MAXN = 1000000+5;char str[MAXN]; int N,sa[MAXN],tax[MAXN],M; int pool1[MAXN],*rk = pool1,pool2[MAXN],*tp = pool2;inline void sort(){FOR(i,0,M) tax[i] = 0;FOR(i,1,N) tax[rk[i]]++;FOR(i,1,M) tax[i] += tax[i-1];ROF(i,N,1) sa[tax[rk[tp[i]]]--] = tp[i]; }inline void SuffixSort(){M = 75;FOR(i,1,N) rk[i] = str[i]-'0'+1,tp[i] = i;sort();for(int w = 1,p = 0;p < N;w <<= 1,M = p){p = 0;FOR(i,1,w) tp[++p] = N-w+i;FOR(i,1,N) if(sa[i] > w) tp[++p] = sa[i]-w;sort();std::swap(tp,rk);rk[sa[1]] = p = 1;FOR(i,2,N) rk[sa[i]] = (tp[sa[i-1]] == tp[sa[i]] && tp[sa[i-1]+w] == tp[sa[i]+w]) ? p : ++p;}FOR(i,1,N) printf("%d ",sa[i]); }int main(){scanf("%s",str+1);N = strlen(str+1);SuffixSort();return 0; }

Height 數組

后綴數組如果只能排序的話那貌似沒什么用,大多數后綴數組題目主要還是考察 Height 數組的性質。

首先扔一些定義。。。

表示 號后綴, 表示后綴 和 的最長公共前綴。同時我們繼續沿用上文的 等定義。

定義

如果直接枚舉后綴那還求后綴數組干嘛,所以說我們要考慮能否通過后綴數組求出的信息來線性推出

。

對于

數組有性質 。證明就不證了(筆者太菜不會,其實分類討論一下就可以了)。

代碼:

inline void get(){int j,k = 0;FOR(i,1,N){if(k) --k;int j = sa[rk[i]-1];while(str[i+k] == str[j+k]) ++k;height[rk[i]] = k;} }

經典應用

求任意后綴的最大 lcp

這東西隨便維護一個區間極值就可以了,

查詢。

可重疊最長重復子串

意思是求最長的子串使得在字符串中重復出現過。

根據定義就是 height 數組中的最大值

不可重疊最長重復子串

POJ - 1743
我們來考慮二分答案。假設現在我們二分的答案是

,想判斷是否有 的符合題目要求的子串。

然后考慮在一些地方將 height 分開,保證每一段最小

。分完組之后枚舉一下看看長度是否滿足存在不交的重復子串就可以了。

本質不同的子串數量

注意到子串 = 后綴的前綴。

對于排名為

的后綴,它有 個前綴,但是有 個是和排名為 的后綴的前綴相同的,減去就可以了。

所以答案就是

查看作者更多博客:https://blog.nowcoder.net/rainair

總結

以上是生活随笔為你收集整理的c++ 字符串数组长度排序_数组 | 后缀数组的求法及应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 人妖av在线| 干日本少妇| 国产精品高清在线观看 | www日本在线观看 | 精品国产鲁一鲁一区二区张丽 | 探花国产精品一区二区 | 欧美色图13p| 日本乱码一区二区 | 欧美一区二区在线视频观看 | 91精品91 | 国产明星换脸xxxx色视频 | 久久国内精品视频 | 国产又黄又 | 日韩最新网址 | 日本 片 成人 在线 九色麻豆 | 无码任你躁久久久久久久 | 小sao货水好多真紧h无码视频 | 日本精品人妻无码免费大全 | 亚洲一二三区在线 | 超级碰碰97 | √8天堂资源地址中文在线 欧美精品在线一区二区 | 伊人久久97 | 国产探花一区二区 | 精品黄色在线观看 | 涩涩五月天 | 亚洲成a人片在线 | 中文字幕第一区综合 | 国产色婷婷一区二区 | 亚洲无限码 | a三级黄色片 | 国产精品欧美精品 | 日韩亚洲欧美精品 | 欧美日韩91 | 在线观看黄网 | 小早川怜子一区二区三区 | 久久久精品综合 | 欧美色综合天天久久综合精品 | 久久精品一区二区 | 精品成人av一区二区在线播放 | 国产r级在线观看 | 人妖videosex高潮另类 | 日日碰狠狠添天天爽无码av | 黄大色黄大片女爽一次 | 色之久久综合 | 亚洲天堂色| 91精品国自产在线 | 国产一区二区av在线 | 日本久久久网站 | 色乱码一区二区三区熟女 | 视频在线观看免费大片 | 中国毛片基地 | 久久久久久久久久综合 | 亚洲国产成人va在线观看天堂 | 中文资源在线观看 | 99色综合网| 爽爽影院在线免费观看 | 国产少妇自拍 | 就要操av| 国产美女www爽爽爽 www.国产毛片 | 亚洲视频手机在线观看 | 狠狠躁18三区二区一区视频 | 97精品久久久| 被两个男人吃奶三p爽文 | 97狠狠操| 欧美日视频 | 毛片毛片毛片毛片毛片毛片毛片 | 精品一区二区视频 | 亚洲一区91 | www亚洲天堂 | 性涩av| 一区精品在线观看 | 久久伊人精品视频 | 欧美成人午夜剧场 | 国产肉体xxxx裸体784大胆 | 魔女鞋交玉足榨精调教 | 欧美老熟| 91精品中文字幕 | www.超碰在线观看 | 国产一级特黄毛片 | 色呦呦麻豆 | 国产乱人乱精一区二视频国产精品 | 在线观看网站污 | 国产成人综合网 | 午夜欧美精品 | 美女啪啪免费视频 | 欧美 中文字幕 | 特级毛片网站 | 在线色站 | 精品毛片一区二区三区 | 69精品久久久久久久 | www.jizz国产 | 亚洲免费看片 | 91理论片| jizz性欧美17| 久久神马影院 | 成人午夜在线视频 | 午夜免费福利视频 | аⅴ资源中文在线天堂 | 高h亲子乱h|