- 博客(25)
- 收藏
- 关注
原创 最长公共子串(后缀数组+LCP)
求两个串的最长公共子串,我们可以将两个串中间插入一个两个串都没有的字符串起来,然后计算出他的后缀数组(sa)和高度数组(lcp),不在同一串中的sa中相邻后缀的最长公共前缀(即高度数组的最大值)就是两个串的最长公共子串。#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int max
2017-08-19 18:50:39 899
原创 最长回文子串(Manancher算法)
计算回文子串的方法有很多,比如将该串反转后拼接在一起利用后缀数组,这里用一个O(n)的算法 首先这个算法为了将奇数串和偶数串放一起考虑,在每个字符的之间都加入了一个该字符串不存在的字符,如: aabbaa #a#a##b#b#a#a# 这样,所有的串都变成了奇数的形式 我们定义如下变量: p[maxn]:存储以i位置为中心的最长回文半径 id:表示当前最长回文串的中心位置 mx:
2017-08-19 16:47:05 873
原创 高度数组(后缀数组伴侣lcp)
利用后缀数组和尺取法求得相邻两个后缀数组之间的最长公共前缀,计入lcp数组,求整个串从i到j的最长公共前缀就是一个标准的RMQ问题。int rank[maxn];void lcp(char*s, int *sa, int *lcp) { int n = strlen(s); for (int i = 0; i <= n; i++) rank[sa[i]] = i; int
2017-08-18 18:30:44 513
原创 后缀数组(倍增法+基数排序思想)
我们只要记录字符串每个后缀的起始位置,就可以表示字符串的每一个后缀。将这种表示按照后缀的字典序排序,就得到了后缀数组。下面用倍增法求后缀数组,每次计算从i开始,长度为k的字符串的字典序rank(i,k)利用基数排序的思想,我们已经计算好了rank(i,k),然后我们在rank(i,k)的基础上,rank(i+k,2k)进行排序,得到的排序结果就是rank(i,2k)的结果。下面代码给出了O(n*lo
2017-08-18 13:19:12 857 1
原创 AC自动机(trie+KMP)
AC自动机可以在线性时间内匹配多个模式串,算法思路是一个在trie上使用KMP算法 trie的讲解和AC自动机算法具体讲解(dalao的帖子) http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html//hdu2222#define clr(a,x) memset(a,x,sizeof a)struct Aho {
2017-08-17 18:16:08 474
原创 KMP算法
KMP算法是一种字符串模式匹配算法,旨在通过子串来发现不匹配的情况下,下一次模式串应该移动的距离,来减少回溯。 因为这个距离是模式串所决定的,与匹配串无关,所以我们对模式串做一个预处理,可以得到一个next数组如下 -1 j=0 max{k|i
2017-08-12 21:57:16 168
原创 种子填充(floodfill)
#define clr(a,x) memset(a,x,sizeof a)char a[100][100];pair<int, int> que[maxn];bool used[100][100];int n;void print() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) {
2017-08-12 17:09:09 1005
原创 最长上升子序列(LIS)
问题描述:给出一个数列,找出这个数列中最长上升子序列中所包含的个数。 很容易能想到一个dp的方法: dp[i]=以i为末尾的最长上升子序列 但是该方法复杂度为O(n^2),我们发现上升子序列末尾的数字越小,它后面就越有优势,所以我们可以转而求在相同长度下,末尾元素的最小值。该算法的复杂度也为O(n^2),但因为dp数组是单调递增的,我们可以用二分的方法来进一步优化,这样时间复杂度就是O(n*l
2017-08-11 21:35:40 217
原创 01背包,完全背包,多重背包(O(V*n))
01背包有n种重量和价值分别为w[i]和v[i]的物品,每种各一个。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案的价值总和最大值。思路:容易得到该问题的状态转移方程为dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]) 其中dp[i][j]表示从前i个物品中挑选出总重量不超过j的物品时总价值的最大值。int w[maxn];int v[maxn];
2017-08-10 22:50:51 622
原创 栈和队列
栈栈的操作: 1. push(x):插入数据 2. pop(x):弹出数据 3. top(x):获得栈顶数据 4. is_empty():判断栈是否为空 5. is_full():判断栈是否已满int s[maxn];int top=0;bool is_empty(){ return top==0;}bool is_full(){ return top>=
2017-08-10 21:19:10 156
原创 滑动窗口最值(单调队列)
问题:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。 解法:利用单调队列来保存未过期(在w窗口内)的之前的最大值,如果当前值大于该值,就从队首弹出,直到找到大于当前值得位置,将当前值的位置压入队首,如果数据过期,就从队尾删除。(单调队列)int a[maxn];int n;int w;deque<int> q;void solve() { for (int i =
2017-08-09 21:46:08 275
原创 getMin功能的栈
stack<int> stackData;//存放栈数据stack<int> stackMin;//存放栈的最小值void push(int x) { stackData.push(x); if (stackMin.empty()) stackMin.push(x); else if (x < stackMin.top()) stackMin.push(x); el
2017-08-09 19:49:02 259
原创 并查集
int par[maxn];//父节点int deep[maxn];深度void init(int n) { for (int i = 0; i < 0; i++) { par[i] = i; deep[i] = 0; }}int find(int x) { if (par[x] == x) { return x;
2017-08-06 19:23:46 155
原创 最长公共子序列(DP)
dp[i][j]表示s串的前i个字符和t串的前j个字符的最长公共子序列 则当s[i]==t[j]时,dp[i+1][j+1]=dp[i][j]+1 当s[i]!=t[j]时,dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);char s[maxn],t[maxn];int n, m;int dp[maxn][maxn];void solve
2017-08-04 22:58:38 200
原创 全排列的求法(DFS)
A为输入的一组数 used用来标记A中第i个数是否已经被用过 perm数组用来存放已经生成的排列 DFS(x,n)是新的排列第x位的数int A[maxn];bool used[maxn];int perm[maxn];bool f = false;void dfs(int x,int n) { if (x == n) { for (int i = 0; i <
2017-08-04 18:22:11 313
原创 幂取模
可以每乘一次取一次模的方式来求一个数幂的模,时间复杂度为O(n),但是当n很大时,算法不是很理想,下面用分治的方法来求,其复杂度为O(logn)int pow_mod(int a, int n, int m) { if (n == 0) return 1; ll x = pow_mod(a, n / 2, m); int ans = x*x%m; if (n % 2
2017-08-03 19:32:16 446
原创 大整数取模
设y为任意整数,x mod m=d 因为 (x*y) mod m =(x mod m)y=(x mod m)(y mod m)mod m 则有: y*(x mod m)=(y*d) mod m 将大数abcd分解为((((a*10)+b)*10+c)*10+d)然后从前向后求模即可int div_mod(char s[], int m) { int ans = 0; for
2017-08-03 01:30:15 527
原创 快速幂的递归和非递归写法
int pos(int x,int n) { if (n == 0) return 1; int res = pos(x*x, n / 2); if (n & 1) res *= x; return res;}int pos(int x, int n) { int res = 1; if (n == 0) return 1; while (
2017-08-01 19:19:05 596
原创 GCD与LCM,extGCD
int gcd(int x, int y) { if (x < y) swap(x, y); while (y > 0) { int r = x%y; x = y; y = r; } return x;}int lcm(int x,int y){ return x / gcd(x, y)*y;}
2017-08-01 18:45:25 258
原创 分治法求RMQ
int findMaximum(int A[], int l, int r) { int m = (l + r) / 2; if (l == r - 1) return A[l]; else{ u = findMaximum(A, l, m); v = findMaximum(A, m, r); return m
2017-08-01 18:36:13 267
原创 二分查找
int bsearch(int A[], int l, int r,int a) { int m = (l + r) / 2; if (A[m] == a) return m; else if (A[m] > a) bsearch(A, l, m, a); else bsearch(A, m, r, a); return -1;}
2017-08-01 18:32:57 133
原创 归并排序
分治法将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。归并排序利用分治法的思想,将待排序的元素递归的分成两个子问题解决,然后将这些子问题的解合并,得到排序的结果。合并操作:将A[ p, q],A[ q+1, r]合并到A const int maxn = 1010;const int INF = 100000000;int L[
2016-04-26 21:12:45 103
原创 插入排序
插入排序插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。类似于我们平时玩牌是整牌。 void Insert_Sort(int A[],int n){ for (int i = 1; i < n; i++){ int key = A[i]; int j = i - 1; w
2016-04-25 21:35:34 83
原创 第一节 搜索算法基础
搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。
2015-07-08 17:03:46 136
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人