二分、倍增、滑动窗口等基础算法
文章平均质量分 61
二分、倍增、滑动窗口、搜索模拟等基础算法
爱寂寞的时光
这个作者很懒,什么都没留下…
展开
-
摊还算法——贡献转移
贡献转移在计算每个元素的作用的时候,我们可以通过反向枚举作用效果,添加到作用元素的身上,这种方法叫做贡献转移。更正式的说,设aia_iai为每个元素的作用数,集合BBB为作用效果,那么:ai=∑b∈B,b→ai1a_i = \sum_{b \in B,b \to a_i} 1ai=b∈B,b→ai∑1例题LeetCode 5874考虑每一个位置的 pivot ,如果iii位置能够成为 pivot 的话,那么前后肯定存在一个位置jjj,将位置jjj变成kkk之后,该位置的 pivot 成原创 2021-10-04 17:19:15 · 155 阅读 · 0 评论 -
括号序列问题
括号序列问题括号序列与前缀和将(和)分别看成是111和−1-1−1,得到一个数字序列,对这个数字序列做前缀和,可以通过这个前缀和判断其任意子序列是否合法。子序列合法等价于psum[r]−psum[l−1]=0psum[r] - psum[l - 1] = 0psum[r]−psum[l−1]=0并且mini=lrpsum[i]−psum[l−1]≥0\min_{i=l}^r psum[i] - psum[l - 1] \geq 0mini=lrpsum[i]−psum[l−1]≥0。其后者可以使用原创 2021-09-03 19:22:22 · 431 阅读 · 0 评论 -
单调优先队列
单调优先队列单调优先队列不同于普通二叉堆实现的优先队列,其复杂度为O(nlogn)O(n \log n)O(nlogn)预处理,O(1)O(1)O(1)时间取堆顶,O(1)O(1)O(1)时间插入。并且数据必须满足每次插入的数据是单调的。思路我们先对数据进行排序,准备两个队列PPP和QQQ,将排序好的数据放入PPP队列中,然后每次取出都比较一下PPP和QQQ的队首元素,取最小/最大的那个并出队,插入的时候向队列QQQ插入到队尾部,由于每次插入的数据都是单调的,因此我们得到的是两个单调的队列,相当于归原创 2021-08-12 14:00:14 · 110 阅读 · 0 评论 -
贪心算法模型总结
贪心算法——调度安排问题应用贪心算法最多的就是顺序安排问题,也是最难的一类问题,问题形式变化多样。其一之任务开始结束时间固定,同一时间只能做一个,最多能做几个?此问题的贪心策略是按照任务的结束时间从小到大排序,因为先做完把时间让给后面,后面的任务就有可能做完。以下问题不做说明均为同一时间只能做一个。其二之每个任务必须做,开始结束时间不固定,但是每个任务所花费的时间固定,并且设每个任务的截止时间为ddd,设这个任务的完成时间为xxx,那么我们这个任务的奖励为d−xd-xd−x,问总计奖励的原创 2021-08-11 09:25:21 · 1242 阅读 · 0 评论 -
离线莫队算法
离线莫队算法离线莫队算法用于解决区间查询问题,核心思想是,如果我们已知区间[l,r][l,r][l,r]内的答案,如果我们能在O(1)O(1)O(1)时间内转移到[l,r+1][l,r+1][l,r+1],[l,r−1][l,r-1][l,r−1],[l−1,r][l - 1,r][l−1,r]或者[l+1,r][l + 1,r][l+1,r]即相邻区间内,那么我们就可以通过这种区间转移的方式求出所有区间的答案,其核心还是尽可能的利用已知,而不是去重复求解。区间转移我们设计双指针算法,利用lll和rr原创 2021-07-09 11:14:00 · 307 阅读 · 0 评论 -
摩尔投票法
摩尔投票法任给无序投票记录,在O(n)O(n)O(n)时间复杂度内,O(1)O(1)O(1)空间复杂度内找到票数最多的候选者,该算法称为摩尔投票法,用于求众数。过程定义两个变量candcandcand和cntcntcnt,分别为当前候选人和候选人的票数,初始化均为000,之后我们依次扫描这个投票记录,如果cntcntcnt为000,那么让candcandcand成为当前记录的候选者,并将cntcntcnt加111。如果遇到相同候选者的投票,那么将cntcntcnt加1,否则减111。这个阶段叫做pai原创 2021-07-09 09:45:58 · 101 阅读 · 0 评论 -
三指针尺取法
三指针尺取法双指针尺取法只能维护单一区间的答案,有时我们需要维护两个区间的答案,这时候就需要三指针尺取法。通常来说,用一个指针代表共用的区间右端点,另外两个区间分别表示两个区间左端点。例题LeetCode 930class Solution{public: int numSubarraysWithSum(vector<int> &nums, int goal) { int l1 = 0, l2 = 0, r = 0; int原创 2021-07-08 19:49:42 · 117 阅读 · 0 评论 -
高级搜索算法
高级搜索本文介绍双向搜索,启发式搜索等高级搜索代码,以BFS、DFS为基础的高级搜索算法。双向搜索双向搜索的主要思想是设立两个端点,一般是搜索的起点和终点。对两个端点同时进行搜索,以缩小搜索空间。双向BFS搜索设立两个队列,分别保存从两个端点扩展的结果。如图:可以看见,搜索空间显著比普通的BFS搜索少了。基本模板:d1、d2 为两个方向的队列m1、m2 为两个方向的哈希表,记录每个节点距离起点的 // 只有两个队列都不空,才有必要继续往下搜索// 如果其中一个队列空了,说明原创 2021-06-30 20:09:13 · 544 阅读 · 0 评论 -
最小相邻交换与逆序对
最小相邻交换与逆序对给定一个排列TTT,给定另外一个排列T′T'T′,其中两个排列中的元素相同,问只能交换相邻元素,最小的交换步骤是多少,使得两个排列的元素位置相同。不同元素如果两个排列元素不存在相同元素,那么我们可以给排列TTT,重新标号为1,2,…,n1,2,\ldots,n1,2,…,n的一个排列,变成一个映射,那么T′T'T′也对应着另外一个排列,那么最小的交换数为T′T'T′对应着另外一个排列的逆序对数。证明:我们可以通过 num\textit{num}num 包含的「逆序对」的数量来得原创 2021-05-06 17:50:04 · 1184 阅读 · 0 评论 -
枚举技巧——积分图
枚举技巧——积分图很多时候,我们会处理矩阵上问题,大部分都是寻找一个可行最优子矩形区域。如果枚举两个顶点时间复杂度为O((NM)2)O((NM)^2)O((NM)2)。下面介绍一种积分图的方式。积分图我们枚举上下两个边界,将边界围成的矩形压成一个数组,至于同列的数据怎么合并,还要看题目的具体要求。之后,我们面对的就是一个一维问题了,相对来说,同等的一维问题更好解决,一般是使用DP求解。这样一来,时间复杂度就是O(N2M)O(N^2M)O(N2M)。时间复杂度降低了一个等级。如果列数比较少,行数比原创 2021-04-22 20:08:05 · 161 阅读 · 0 评论 -
桶思想
桶思想班级里有nnn个同学,每个同学都有一个生日,老师想快速的知道有没有人的生日间隔在一个月内,该怎么做呢?把每年365天分成12个月(就相当于12个桶),每个月(桶)内的生日都是满足的,并且相邻两个月也可能满足,除了这两种情况都不满足了。这就是桶思想。例题LeetCode 220我们将整数范围内的值按照绝对值不大于ttt分桶,我们发现桶的大小为t+1t+1t+1即可,并且桶的元素最多有一个,因此我们可以使用哈希表实现。特别的,注意计算桶的编号,负数需要先加111再减去111,保证结果计算正确。原创 2021-04-17 15:03:26 · 591 阅读 · 0 评论 -
离散化数据
离散化数据离散化本质上可以看成是一种 哈希,其保证数据在哈希以后仍然保持原来的全/偏序关系。通俗地讲就是当有些数据因为本身很大或者类型不支持,自身无法作为数组的下标来方便地处理,而影响最终结果的只有元素之间的相对大小关系时,我们可以将原来的数据按照从大到小编号来处理问题,即离散化。用来离散化的可以是大整数、浮点数、字符串等等。用数学的定义来讲,两个关联偏序集集合分别为S1S_{1}S1和S2S_{2}S2,且存在一一映射关系。对集合S1S_{1}S1运用变换TTT,那么S2S_2S2的偏序集原创 2021-04-14 21:26:46 · 466 阅读 · 0 评论 -
图上倍增
图上倍增在一个有向图、无向图上进行倍增。一般设数组G[i][j][k]G[i][j][k]G[i][j][k],表示是否有从i→ji \to ji→j的路径,且路径的长度为2k2^k2k.更新方法:最外层枚举kkk,内层枚举点对i,ji,ji,j,最内层枚举中间点ttt,使得G[i][j][k]=G[i][t][k−1]ANDG[t][j][k−1]G[i][j][k] = G[i][t][k-1] AND G[t][j][k-1]G[i][j][k]=G[i][t][k−1]ANDG[t][j][k原创 2021-04-08 21:15:56 · 174 阅读 · 0 评论 -
最近公共祖先LCA
最近公共祖先LCAP3379 最近公共祖先LCA给定一有根树,给定两个点,求这两个节点的最近公共祖先。倍增法定义一个数组fa[i][e]fa[i][e]fa[i][e],表示第iii个节点,沿着i→ri \to ri→r的路径走2e2^{e}2e步的祖先节点,类比与STSTST表,2e+12^{e}+12e+1就是路径长度。特别的,e=0e=0e=0的时候表示节点的父节点。然后通过DFSDFSDFS遍历的方式计算出整棵树的fafafa数组,通过一下公式:fa[i][e]=fa[fa[i][e−1原创 2021-03-04 11:45:28 · 87 阅读 · 1 评论 -
算法思想-极大化极小
算法思想-极大化极小简单来说就是假如答案要求的是最大解,我们可以从反面考虑,考虑最小的反面,就是最大的正面,这种方法叫极大化极小。尤其在博弈论中最为常见。问题LeetCode 1423此题我们可以从n-k个剩余卡片中,求得和最小的滑动窗口,此时就是最大的答案。...原创 2021-02-06 10:53:36 · 517 阅读 · 0 评论 -
滑动窗口解题模板
滑动窗口解题模板问题Leetcode 1208解题模板#include <bits/stdc++.h>using namespace std;class Solution{public: int equalSubstring(string s, string t, int maxCost) { int sum = 0; int ans = 0; int st = 0; int ed = 0;原创 2021-02-05 14:48:01 · 129 阅读 · 0 评论 -
循环不变式
循环不变式何为循环不变式?类比于数学中的数学归纳法。循环不变式分为三个部分,分别是初始化、保持、终止。初始化:在没有进入循环之前,这个循环不变式依然满足不变的属性。保持:在每一次循环开始之前,这个循环不变式依然满足不变的属性。终止:循环可以被证明终止,终止时,这个循环不变式依然满足不变的属性,此时就是答案的解。因此,在三个部分重复的一句话就是,这个循环不变式依然满足不变的属性。循坏不变式在任何时候都保持不变的特征。循环不变式是证明算法正确性的一个重要的方法,也是设计迭代算法重要的一依据。原创 2021-01-27 23:36:27 · 772 阅读 · 0 评论 -
从零开始的二分法
第一关:递归先来一个基本的二分法,用递归写出二分法:int bsearch(vector<int> &nums, int l, int r, int target){ // 在区间[l,r)进行搜索}算法一:递归的左闭右开区间搜索不错,我们继续,试试闭区间内搜索:int bsearch(vector<int> &nums, int l, int r, int target){ // 在区间[l,r]进行搜索}算法二:递归的闭区间原创 2020-12-26 15:11:54 · 117 阅读 · 0 评论