几种常用字符串算法
2016-07-10 15:42
302 查看
去年写的,已经发霉,出来晾一晾…
先定义T(i,k)表示一个以i为起点,长为k的串。
环形字符串s复制一遍后接在后面,将环转换为链。
设以T(i,k)为最优解,T(j,k)是待比较的解(i < j)。当k≥N时,匹配完成。
当T(i,k-1) = T(j,k-1),要比较字符s[i+k]与s[j+k]
若s[i+k] = s[j+k],则k++继续往后比较;
若s[i+k] < s[j+k],则T(i,k)为最优,重新给j赋值为j+k+1,不可能更小。
若s[i+k] > s[j+k],则T(j,k)为最优,i←j,j←max(j,i+k)+1,即j只需跳到未被比较过的位置
长春网络赛1006是求一个串的最大表示方案。可以逆时针和顺时针两种方式。
KMP
模式串P在母串S上的匹配。#define M 100000 int pre[M], n, m; void set(string p) { memset(pre, 0, sizeof(pre)); pre[0] = -1; int m = p.length(); for(int i = 1;i < m;i++) { int j = pre[i-1]; while(j >= 0 && p[j+1] != p[i]) j = pre[j]; pre[i] = p[j+1] == p[i] ? j+1:-1; } } int KMP(string s, string p) { set(p); int j = -1, r = 0, n = s.length(), m = p.length(); for(int i = 0;i < n;i++) { while(j >= 0 && s[i] != p[j+1]) j = pre[j]; if(s[i] == p[j+1]) j++; if(j == m-1) { r++; j = pre[j]; } } return r; }
最小字典序表示
找到一个自循环串的最小表示。先定义T(i,k)表示一个以i为起点,长为k的串。
环形字符串s复制一遍后接在后面,将环转换为链。
设以T(i,k)为最优解,T(j,k)是待比较的解(i < j)。当k≥N时,匹配完成。
当T(i,k-1) = T(j,k-1),要比较字符s[i+k]与s[j+k]
若s[i+k] = s[j+k],则k++继续往后比较;
若s[i+k] < s[j+k],则T(i,k)为最优,重新给j赋值为j+k+1,不可能更小。
若s[i+k] > s[j+k],则T(j,k)为最优,i←j,j←max(j,i+k)+1,即j只需跳到未被比较过的位置
string smallest(string s, int &ans) { int i, j, k, l; int N = s.length(); s += s; for(i = 0, j = 1;j < N;) { for(k = 0;k < N && s[i+k] == s[j+k];k++); if(k >= N) break; if(s[i+k] < s[j+k]) j += k+1; else { l = i+k; i = j; j = max(l, j) + 1; } } ans = i; return s.substr(i, N); }
//也可不调换ij int smallest(string s) { int i, j, k, l; int N = s.length(); s += s; for(i = 0, j = 1;j < N && i < N;) { if(i == j) j++; for(k = 0;k < N && s[i+k] == s[j+k];k++); if(k >= N) break; if(s[i+k] < s[j+k]) j += k+1; else i += k+1; } return min(i, j); }
长春网络赛1006是求一个串的最大表示方案。可以逆时针和顺时针两种方式。
字典树
复杂度O(N),适合插入与查询。void insert(char *s, int l, int t, int x) { if(t == l) { strcpy(a[x].word, s); a[x].end++; return; } if(a[x].son == 0) { size++; a[x].son = size; a[size].ch = s[t]; insert(s, l, t+1, size); return; } int i = a[x].son; if(a[i].ch > s[t]) { size++; a[x].son = size; a[size].next = i; a[size].ch = s[t]; insert(s, l, t+1, size); return; } int j = i; while(a[i].ch < s[t] && a[i].next != 0) { j = i; i = a[i].next; } if(a[i].ch < s[t]) { size++; a[i].next = size; a[size].ch = s[t]; i = size; } else if(a[i].ch > s[t]) { size++; a[j].next = size; a[size].next = i; a[size].ch = s[t]; i = size; } insert(s, l, t+1, i); return; } void read(int x) { if(a[x].end) printf("%s %.4f\n", a[x].word, 100.0*a[x].end/sum); if(a[x].son) read(a[x].son); if(a[x].next) read(a[x].next); }
AC自动机
在字典树上的KMPstruct Trie { int next[WN][AL], fail[WN], end[WN]; int root, L; int newnode() { for(int i = 0;i < AL;i++) next[L][i] = -1; end[L++] = 0; return L-1; } void init() { L = 0; root = newnode(); } void insert(char buf[], int x) { int len = strlen(buf); int now = root; for(int i = 0;i < len;i++) { if(next[now][buf[i]-'A'] == -1) next[now][buf[i]-'A'] = newnode(); now = next[now][buf[i]-'A']; } end[now] = x; } void build() { queue<int> Q; fail[root] = root; for(int i = 0;i < AL;i++) if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } while(!Q.empty()) { int now = Q.front(); Q.pop(); for(int i = 0;i < AL;i++) if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } int query(char buf[]) { int len = strlen(buf); int now = root; int res = 0; for(int i = 0;i < len;i++) { now = next[now][buf[i]-'A']; int temp = now; while( temp != root ) { res += end[temp]; end[temp] = 0; temp = fail[temp]; } } return res; } }ac;
相关文章推荐
- MULTI-INTERFACE CONNECTIVITY ON ANDROID - ConnectivityManager
- 如何使用xcode将应用安装到IPhone上
- o(n)指针法替换空格
- QML UI布局管理
- Android 计算器解析(二): 加入计算功能
- PHP smarty
- C++类的成员函数存储方式(是否属于类的对象)
- xcorr()详解
- Linux内核内存管理-内存访问与缺页中断【转】
- Lucene5学习之LuceneUtils工具类简单封装的例子
- 【CQ模拟赛】密码
- Qt 中update()和repaint()的区别
- TCP/IP协议簇分层详解
- ubuntu 终端log 打印 保存
- 如何正确删除虚拟机上的系统
- SQL 约束
- Linux学习总结—缺页中断和交换技术【转】
- Ubuntu下Eclipse安装与编译ns-3遇见的各种问题
- spark 第一个java程序
- C#随机生成验证码方法