面试笔试中的重要算法合集
基础算法
1.快速排序(超级重要,手撕)
- 可能会有“第K个数”的改编
2.归并排序(一般重要)
“逆序对的数量”不看
3.二分
笔试多,面试不多
只看“数的范围”
4.高精度
看个加法就可以了
5.前缀和与差分
- 前缀和(最重要)
- 子矩阵的和(二维的)
- 差分(一般重要)
6.双指针算法(超级重要)
面试,笔试会问
7.位运算
其他题可能会用到
8.区间合并
超级重要,面试会问
数据结构
1.栈
看“表达式求值”就可以了。
或者
看“括号匹配”
2.Trie
面试会问-“大数据量的排序”
3.并查集
笔试中的难题
搜索与图论
1.DFS(最重要)
2.BFS
3.树与图的深度优先遍历-DFS
题目描述:树的重心
给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
输入格式
第一行包含整数 n,表示树的结点数。
接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。
输出格式
输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。
数据范围
1≤n≤105
输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4
代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
// N代表节点数量, M代表边的数量,树是无向连通图
const int N = 100010, M = N * 2;
int ans = N; // 定义答案
// 注意一条边有两个节点
int h[N];//表示第i个节点的 第一条边的 idx
int e[M]; // 表示 第 idx条边的 end节点下标
int ne[M]; // 表示与第idx条边 同一起点的节点的下一条边的idx
int idx; // 边的下标索引
bool st[N]; // 存放该点是否已被遍历的状态数组
int n;
// 树的深搜,返回的是去掉u节点后剩余连通图中节点的最大值
int dfs(int u){
st[u] = true; // 标记该点已被遍历
int sum = 1; // 当前子树(连通块)所具备的节点数量,初始为1
int res = 0; // 初始化 将该点删除后剩余连通块的点数的max
// 遍历以u开始的链表的所有边
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i]; // 获取该边的end节点的下标
// 如果该点没有被遍历过,就遍历他
if(st[j]) continue;
else{
int s = dfs(j);
// 记录所有连通块的最大值
res = max(res, s);
sum += s; // 当前遍历到的子树的max是u的树的一部分
}
}
res = max(res, n - sum);//n-sum代表u节点父节点以上的连通块中节点数量
ans = min(ans, res);
return sum;
}
// 添加一条边,该边的起点下标是a,终点下标是b
void add(int a, int b){
e[idx] = b; // 该边的下标应该是idx,将该边的终点节点 记成 b
ne[idx] = h[a]; // 由于每个节点都会以其为头创建一个链表,将该边插入到a节点开头
h[a] = idx ++; // 将a节点的链表的头指向当前的边,并将边的下标++,准备指向下一条边
}
int main(){
memset(h, -1, sizeof h);
// 处理输入输出
cin >> n;
for(int i = 0; i < n - 1; i ++){
// 添加一条边
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1);
cout << ans << endl;
return 0;
}
4.树与图的广度优先遍历-BFS
5.拓扑排序
笔试会考,面试一般不会
6.Kruskal
笔试会考
动态规划
“状态压缩”不看
数位统计不看
背包和线性DP最重要