算法笔记本

书写规范

别在同一行定义多个变量

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];

变量的减少

分为三段 : 
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;
posted @ 2022-04-15 18:02  miyanyan  阅读(25)  评论(0编辑  收藏  举报