算法与数据结构
1.题目
- 洛谷
- 杭电
- 牛客网
- leeCode
2.书籍
- 课本
- 刘汝佳
- 白皮书
- 算法导论
一.字符串
1.KMP算法
- 笔算next数组
- 如果数组是从1开始
- max{前缀和后缀相等的长度} + 1为当前字符的next值
- 如果数组从0开始
- **max{前缀和后缀相等的长度}**为当前字符的next值
- 如果数组是从1开始
- 例如
a | b | a | b | c | a | b | a | |
---|---|---|---|---|---|---|---|---|
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
k | 0 | 1 | 1 | 2 | 3 | 1 | 2 | 3 |
kt | -1 | 0 | 0 | 1 | 2 | 0 | 1 | 3 |
例如对于i = 5时
后缀为: b, ab, bab
前缀为: a, ab, aba
最大相同前缀为 ab,长度为2所以为 k = 3
同理, 如果下标从0开始就是kt。
-
代码
i = 0; j = next[0] = -1; //求每个字符的最大匹配的前后缀 while(i < s.length()){ if(T[i] == T[j] || i == -1){ i++; j++; next[i] = j; } else { j = next[j]; //回溯 } }
例如 :
i = 4, 5, *, *, 6
j = 2, 3, 1, 0,1
-
优化
对于 aaaab,
next[] = {0, 1, 2, 3, 4}
但是如果 2 失败,回溯到1仍旧失败,回溯到0还是会失败。
就是比较最大前后缀之后看看这个字符是不是和匹配前缀的后一字符相等,如果相等就回溯。
-
改进代码
i = 0; j = next[0] = -1; //求每个字符的最大匹配的前后缀 while(i < s.length()){ if(j == -1 || T[i] == T[j]){ i++; j++; if(T[i] != T[j]){ next[i] = j; }else next[i] = next[j]; } else { j = next[j]; //回溯 } }
6.完整代码
//回溯法进行匹配 char t[] = {'a','a','a','a','b'}; //匹配串 char s[] = {'c','d','a','a','a','a','b',}; //原串 int next[256]; void get_next(int length){ int i = 0, j = -1; next[0] = -1; while(i < length){ if(j == - 1 || t[i] == t[j]){ i++;j++; if(t[i] != t[j])next[i] = j; else next[i] = next[j]; }else j = next[j]; } } int KMP(int sl, int tl){ int i = 0, j = 0; while(i < sl && j < tl){ if(j == -1 || s[i] == t[j]) { i++; j++; }else j = next[j]; } if(j == tl)return i - j; else return -1; }
-
练习
- 子串
- 字符串的拼接
s.append()
- 字符串的增加字符
s.push_back()
- 使用进制转换与字符串的结合问题
- 字符串的拼接
- 子串
二.树
1.二叉树
- 性质:
2.线段树
3.树状数组
1.单点修改区间查询
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+100;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
ll a[N],b[N],c[N],n;
int lowbit(int k)
{
return k&-k;
}
void add(int p)
{
while(p <= n){
c[p] ++;
p += lowbit(p);
}
}
ll sum(int p)
{
ll ans = 0;
while(p){
ans += c[p];
p -= lowbit(p);
}
return ans;
}
bool cmp(const int &x,const int &y)
{
return b[x] < b[y];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for(int i = 1;i <= n;i ++) cin >> b[i] ,a[i] = i;
sort(a + 1,a + n + 1,cmp);
ll ans = 0;
for(int i = 1;i <= n;i ++){
add(a[i]);
ans += i - sum(a[i]);
}
cout << ans;
return 0;
}
2.区间修改区间查询
3.区间修改单点查询
4.区间修改区间查询
4.树的遍历
5.树的表示
6.二叉搜索树
7.红黑树
8.B树
三.图
1.图的表示方法
2.遍历方法
3.最短路径
4.最小生成树
5.欧拉回路
6.最小生成树
7.表达式树
8.网络流
四.dp
1.背包
2.区间 dp
3.状态压缩 dp
五.递归
六.算法
1.贪心
2.分治
3.查找
4.排序
-
归并排序
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5+100; const int INF = 0x3f3f3f3f; const int mod = 998244353; int a[N],t[N],n; ll ans; void Merge(int l,int r) { if(l >= r) return ; int mid = (l + r) / 2; Merge(l,mid);Merge(mid+1,r); int i = l,j = mid + 1,k = l; while(i <= mid && j <= r){ if(a[i] <= a[j]) t[k++] = a[i++]; else{ t[k++] = a[j++]; ans += (mid - i + 1); } } while(i <= mid) t[k++] = a[i++]; while(j <= r) t[k++] = a[j++]; for(int i = l;i <= r;i ++) a[i] = t[i]; } int main() { scanf("%d",&n); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]); Merge(1,n); cout << ans; return 0; }
5.摊还分析
来源:CSDN
作者:**未来I象限**
链接:https://blog.csdn.net/fuzekun/article/details/104113314