算法笔记本
书写规范
别在同一行定义多个变量
vector<bool> ans, indexes;
sort(indexes.begin(), indexes.end()); // <- 这里sort的其实是一个 vector<bool> !!! 大坑被坑了
思路转变
二维数组
二维数组也是数组,对他的操作其实和一维类似,可以先转成一维再进行后续的操作,比如排序等
除法变乘法
- 定义ans[i]为数组所有元素的乘积除nums[i],即
ans[i] = total / nums[i]
,则可以转换为ans[i] = left[i] * right[i]
,前后缀思想,这样可以解决total过大取模时计算除法很麻烦的问题
2906. 构造乘积矩阵
一条链,A B 从端点往中间会合
假设A在左,B在右,即A = 0, B = n - 1, A 到 B 这条链一共n个节点
可采用时间戳标记,先从B到A,记录经过节点时的时间戳,此时的BTime数组是递减的;
再从A到B,记录以A为起点的时间戳,ATime[cur] < Btime[cur] 意味着 A 先访问 cur 节点
这种方法可以解决树上遍历问题 : 2467. 树上最大得分和路径
子数组
- 子数组的和 -> 先求前缀和 sum[i, j] = pre[j + 1] - pre[i];
变量的减少
- 在前缀和后缀数组中筛选,如果筛选数固定,可转成在中间段刷选,从而变成滑动窗口
1658. 将 x 减到 0 的最小操作数
2516. 每种字符至少取 K 个
分为三段 :
a + b + c = sum;
a + c = x;
x = sum - b;
最初的思路是求 a、c 两个变量,其实只需求 b 一个变量
关键词命中
- “在一维数组中找第一个满足某种条件的数” -> 单调栈
两个变量决定大小,固定一个变量,按优先队列去不断选择
857. 雇佣 K 名工人的最低成本
1383. 最大的团队表现值
条件拆分
(xi, ti) 距 x0 的耗时为abs(xi - x0) + ti
, 给定 (xi, ti) 的数组, 求x0, 使耗时最小
这里t成了一个干扰因素,可以把t拆出来, 将 (x, t) 变成 (x - t, 0) 和 (x + t, 0)
回文串
- 如果一个字符串可任意排序,则判断是否为回文串就是至多一个字母出现奇数次,其余字母出现偶数次
距离覆盖
给定一个数组nums,对nums任意数进行相加,如何得到 [0, maxv] 内的所有数?如果不满足则最少添加多少数?
假设现在得到了[0, s]内的所有数,当前数字为x,则可以得到[x, s + x]内的所有数,于是乎出现两种情况:
- s >= x,这两个区间重叠,无需额外操作
- s < x,产生了间隙[s + 1, x - 1],如何去除这个间隙?为了使添加次数最少,我们应尽可能地让区间更大,所以新加一个s,我们可以得到[0, 2 * s]内的所有数,重复这一步骤,直到与x重叠
在代码实现时,s应从1开始,这样可以避免s*2
如果s为0陷入死循环。
int ans = 0; // 最小添加次数
// 假定nums已排序
int s = 1, index = 0;
while (s <= maxv) {
if (index < nums.size() && nums[index] <= s) {
s += nums[index];
index++;
}
else {
s *= 2;
ans++;
}
}
return ans;