排序
快速排序
- 分治,确定分界点-调整区间-递归左右,不稳定
- 很多边界问题
x=q[l]; -> quicksort(q, l, j); quicksort(q, j+1, r);
x=q[r]或者x=q[(l+r+1)/2]; -> quicksort(q, l, i-1); quicksort(q, i, r);
- 避免一直取到左边界或者右边界
- 调整区间的简单思想:额外开两个数组,左边放一个右边放一个
1 | const int N = 1e6 + 10; |
- 变形:【找出第k个数】
1 |
|
归并排序
- 分治,确定分界点-递归左右-合二为一,稳定
我真的会谢)典错误:写最后的合并的时候顺手加上了自增其实不应该
1 | const int N = 100010; |
查找
🍨整数二分
核心思想
- 初始化:l=0, r=n-1;
- 查找红色区域右边界:
1
2
3
4
5while(l < r){
mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
} - 查找绿色区域左边界:
1
2
3
4
5while(l < r){
mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
} - check函数的设计
- 无解情况
789.数的范围
1 | int a[N], n, q; |
🍰3712.根能抵达的点
二分搜索查找 + 树的dfs
(还存在问题,虽然我不李姐为啥)
1 |
|
浮点数二分
790.数的三次方根
错两位;特殊在左右边界给定
1 | int main(){ |
高精度
加法
791.高精度加法
输入一个$\frac{a}{b}$
减法
乘法
除法
前缀和
一维
- 求前缀和公式:
- 求区间和公式:
1 | const int N = 100010; |
二维
差分
一维
二维
双指针
- 逻辑框架799.最长连续不重复子序列
1
2
3
4for(int i=0, j=0; i<n; i++){
while(j<i && check(i,j)) j++;
// 具体逻辑
}
有点滑动窗口的感觉,涉及到单调性
- 数据大/字母则hash
1 | const int N = 100010; |
位运算
x >> k & 1
:求n的第k位数字(0<=k<=n-1
)lowbit(n) = x & -x
:返回n的最后一位1
离散化
- 过程:
vector<int> alls;
存储所有待离散化数值sort(alls.begin(), alls.end());
排序alls.erase(unique(alls.begin(), alls.end()), alls.end())
去重- 二分确定index
- unique函数自实现:
1 | vector<int>::iterator unique(vector<int>& a){ |
- 离散化
802.区间和
1 |
|
区间合并
803.区间合并
注意这个地方有点问题,虽然我整体思路什么的都是一致的但是发生了玄学问题,后续解决一下。
1 |
|
动态规划
背包问题
- 01背包: 每件物品最多只用一次
- 完全背包: 每件物品有无限个
- 多重背包(优化): $s_i$个
- 分组背包: $N$组
(1) 01背包
1 |
|
优化后: 滚动数组
1 | int f[N]; |
(2) 完全背包
1 |
|
优化后:
1 | int f[N]; |
(3) 多重背包
1 |
|
优化后: 二进制优化
1 | // 注意全局const int变量值没明白 |
(4) 分组背包
1 |
|
线性DP
898.数字三角形
初始化范围注意
1 |
|
895.最长上升子序列
1 | const int N = 1010; |
优化:
另起炉灶:有点类似贪心思路
1 | const int N = 100010; |
897.最长公共子序列
1 | const int N = 1010; |
899.编辑距离
我的错误思路:与最大公共子序列相关(?);
1 |
区间DP
- 框架
1 | // 外层区间长度循环;内层索引循环 |
282.石子合并
1 | const int N = 310; |
计数类DP
338.计数问题