基础算法/思维
基础
chr1st0pher
Dancer on the keyboard
展开
-
Leetcode 46. 全排列
Description求给定排列的全排列Codeclass Solution {public: vector<vector<int>> permute(vector<int>& nums) { vector<vector<int>>res; sort(nums.begin(), nums.end()); do{ res.push_back(nums);原创 2021-03-04 20:42:52 · 180 阅读 · 1 评论 -
Leetcode 1438. 绝对差不超过限制的最长连续子数组(双指针+单调队列)
Description给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。如果不存在满足条件的子数组,则返回 0 。Solution首先发现显然可以用双指针来计算答案,重点在于如何维护当前段内的最大最小值动态维护当前窗口内的最大值和最小值,可以采用单调队列时间复杂度O(N)O(N)O(N)空间复杂度O(N)O(N)O(N)Codeclass Solution {public:原创 2021-03-04 15:20:56 · 264 阅读 · 1 评论 -
剑指 Offer 59 - II. 队列的最大值(单调队列)
Description请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。若队列为空,pop_front 和 max_value 需要返回 -1Solution思路与剑指 Offer 30. 包含min函数的栈 类似,本质上也是相似的空间换时间的套路。维护两个队列,一个是正常队列,一个是非降的单调(双向)队列,若当前要压入队列的元素x比单调队列尾的元素y 大,则弹出队尾元素,并继续判原创 2021-03-01 23:53:46 · 108 阅读 · 0 评论 -
剑指 Offer 51. 数组中的逆序对(BIT + 离散化)
Description在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。Solution比较裸的求逆序对,这里采用的是竞赛中常用的BIT求法时间复杂度:O(NlogN)O(N\log N)O(NlogN)空间复杂度:O(N)O(N)O(N)Codeclass Solution {public: static const int maxn = 5e4 + 7; int lim,bit[maxn];原创 2021-03-01 21:45:47 · 135 阅读 · 0 评论 -
剑指 Offer 49. 丑数(小根堆)
Description我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。111是丑数nnn 不超过169016901690Solution因为要求从小到大的第n个丑数,所以我们采用小根堆,每次弹出当前最小的丑数,并把它的2/3/5倍插入小根堆即可注意还需要判重(set)Codeclass Solution {public: typedef long long ll; set<ll>s; c原创 2021-03-01 21:23:39 · 102 阅读 · 0 评论 -
剑指 Offer 52. 两个链表的第一个公共节点(LCA)
Description输入两个链表,找出它们的第一个公共节点。若不存在则返回NULL要求时间复杂度O(N), 空间复杂度O(1)Solution有点类似寻找LCA,故可借用朴素求LCA的思想,先把两个节点拉到同一深度,再同时向树根跳,第一次相遇的节点就是LCA。因此,本质上我们只需要预先求出两个链表长度的差值,再按照求LCA的方法即可。Code/** * Definition for singly-linked list. * struct ListNode { * int va原创 2021-02-24 01:07:31 · 96 阅读 · 0 评论 -
剑指 Offer 31. 栈的压入、弹出序列(思维)
DescriptionSolution若当前弹出的为x,那压栈队列中x之前的元素肯定已经被压过栈了基于这一点,容易发现:对于当前弹出序列的某一元素x, 若x比之前的弹出序列中在压栈序列中下标最大的元素下标还要大,那此次弹出合法若小于,且当前栈顶元素不等于x,则不合法,反之则合法我们只需要维护当前弹出序列元素在压栈序列中下标最大的元素的下标,并同时维护一个栈即可。时间复杂度:O(N)空间复杂度:O(N)Codeclass Solution {public: static con原创 2021-02-24 00:05:50 · 86 阅读 · 0 评论 -
剑指 Offer 30. 包含min函数的栈(单调栈)
Description定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。Solution光靠一个栈必然是无法实现O(1)查询min的,故我们考虑再加一个栈在维护一个正常的栈sta1的同时,维护一个非减的栈sta2(top是最小值之一)每次查询min的值时即为栈sta2顶的值为什么这样是正确的?假设当前需要push的值为x, 而sta2栈顶的值为y:若x > y,按照我们的设计,x不需要压入原创 2021-02-19 22:28:35 · 93 阅读 · 0 评论 -
剑指 Offer 28. 对称的二叉树(二叉树的镜像)
DescriptionSolution二叉树和它的镜像,实际上就是在层序遍历中每一层是左儿子优先还是右儿子优先的区别实现上,我们这两种遍历方法同时进行,若每次遍历到的节点都相同,则证明一颗二叉树是对称的时间复杂度:O(N)O(N)O(N)空间复杂度:O(N)O(N)O(N)Code/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; *原创 2021-02-19 21:17:30 · 81 阅读 · 0 评论 -
Leetcode 1004. 最大连续1的个数 III (双指针)
DescriptionSolution显然满足双指针中的单调性,即左指针+1的情况下,右指针(非严格)递增Codeclass Solution {public: int longestOnes(vector<int>& A, int K) { int l = 0, r = 0, res = 0; int cnt = K, n = A.size(); if(!K) { int tmp = 0;原创 2021-02-19 21:11:09 · 102 阅读 · 0 评论 -
Leetcode 995. K 连续位的最小翻转次数(贪心 + 双向队列)
DescriptionSolution观察发现,当从头开始处理到第 iii 位(前面的位数都为111)时, 若该位(在考虑被之前的翻转所影响的情况下)为 000,则必须翻转,且是以从第 iii 位开始向后K个长度的翻转(因为前面的位数都为111了,再翻转它们没有任何意义),所以我们可以贪心的进行翻转操作,即可满足最少次数的要求。实现上,采用双端队列的方式,动态维护能影响到当前位的所有翻转,根据现存翻转个数来判断该位的当前值(奇数个则取反,偶数个不变)时间复杂度 O(N)O(N)O(N)空间复杂度原创 2021-02-18 23:35:14 · 168 阅读 · 0 评论 -
剑指 Offer 41. 数据流中的中位数(大根堆+小根堆)
DescriptionSolution经典问题,用一个大根堆和一个小根堆来维护数据流的中位数,稍微手推一下即可Hint priority_queue<int,vector<int>,greater<int> >q2;//小根堆 priority_queue<int,vector<int>,less<int> >q1;//大根堆Codeclass MedianFinder {public: /**原创 2021-02-11 00:45:54 · 175 阅读 · 1 评论 -
剑指 Offer 35. 复杂链表的复制(Map)
DescriptionSolution存在两种拷贝:深拷贝和浅拷贝深拷贝主要是将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为此时它自己在堆中开辟了自己的内存区域,不受外界干扰。浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。而本题需要我们用深拷贝来复制该复杂链表,若每个节点只有一个next指针指向下一个节点,则只需要顺序遍历一遍待拷贝链表,同时复制一份即可;但这里还有一个random指针,所有我们需要同时建立原链表和新链表内存地址的对原创 2021-02-10 22:41:36 · 119 阅读 · 0 评论 -
Leetcode 1423. 可获得的最大点数(前缀和)
DescriptionSolution最终的方案一定是前缀+后缀,故 O(N)O(N)O(N)前缀和枚举即可Codeclass Solution {public: int maxScore(vector<int>& cardPoints, int k) { int sz = cardPoints.size(); vector<int>sum(sz); for(int i = 0;i < sz;++i)原创 2021-02-10 22:19:38 · 154 阅读 · 0 评论 -
Leetcode 567. 字符串的排列(双指针)
DescriptionSolution双指针 + check(), 复杂度O(32∗N)O(32*N)O(32∗N)Codeclass Solution {public: inline bool check(int *sum) { for(int i = 0;i < 26;++i) { if(sum[i] != 0) return false; }return true; } bool checkInclus原创 2021-02-10 22:15:46 · 115 阅读 · 0 评论 -
剑指 Offer 64. 求1+2+…+n (二进制)
DescriptionSolution第一眼觉得有点离谱,啥都不让用;突然想到一种只用加减和移位运算符来模拟乘法的方法,核心思想类似快速乘(龟速乘),将乘数进行二进制差分,对被除数进行移位后再相加。Codeclass Solution {public: typedef long long ll; ll mul(ll a,ll b) { ll res = 0, cnt = 0; res += ((a << cnt) & ((b&a原创 2021-02-05 23:08:47 · 105 阅读 · 0 评论 -
Leetcode 424. 替换后的最长重复字符 (双指针)
DescriptionSolution双指针Codeclass Solution {public: inline int MAX(int a,int b) {return a > b ? a : b;} int get_mx(int *sum) { int mx = 0; for(int i = 0;i < 26;++i) mx = MAX(mx, sum[i]); return mx; } int ch原创 2021-02-03 00:09:20 · 102 阅读 · 0 评论 -
Leetcode 1579. 保证图可完全遍历(思维 + 生成树)
DescriptionSolution首先注意到本题中的“完全遍历”概念本质上就是某人能走的边集为原图的一颗生成树故我们可以借鉴生成树算法的思想:避圈法(也就是kruskal的核心思想)再做思考,可删除的边分为两类,一类是某人独有的边,一类是二人共有的若我们删除某人独有的边,在不影响它本身的“完全遍历”性质的前提下,对另一个人的该性质无影响所以我们若要删除尽可能多的边,就应该优先删除独有边,再删除共有边本题一个不可忽视的条件所有元组 (typei, ui, vi) 互不相同该条件说明原创 2021-01-27 02:37:00 · 198 阅读 · 0 评论 -
Codeforces 1450D. Rating Compression (二分 + 单调栈)
DescriptionSolution猜想:假如满足条件的k的最小值(除1以外) 为 x, 那么大于等于x的k值都满足条件证明:待补用单调栈check的二分来找到这个最小值x时间复杂度:O(N∗logN)O(N * \log N)O(N∗logN)Codeconst ll inf = 2e18 + 7;const int maxn = 3e5 + 7;int n, a[maxn];int head, tail,que[maxn];bool vis[maxn];bool check原创 2020-12-09 17:43:52 · 251 阅读 · 0 评论 -
Leetcode 621. 任务调度器(贪心)
DescriptionSolution先统计一下不同种类的任务出现次数, 在任意时刻,当前剩余次数最多的任务的优先级最高故可贪心的选取当前剩余个数最多的任务(“长作业优先" )Codeclass Solution {public: int leastInterval(vector<char>& tasks, int n) { int num[26];memset(num,0,sizeof(num)); int sz = tasks.s原创 2020-12-05 21:33:49 · 227 阅读 · 0 评论 -
2020 Jiangsu CPC C. Cats(二叉树模拟)
DescriptionExamplesinput1output1input3output1 2 3Solution我们发现1最多出现一次,2最多出现2次,3最多4次…,显然i最多出现(1<<(i-1))次。我们构建一颗满二叉树,每一层的权值都为层数,以中序遍历方式依次取数,直到取到N个数为止Code#include <bits/stdc++.h>using namespace std;typedef long long ll;const int m原创 2020-12-05 13:06:22 · 269 阅读 · 0 评论 -
Leetcode 659. 分割数组为连续子序列(贪心)
DescriptionSolution分割出来的子序列需要尽可能的长,所以我们对于每个数,都贪心的放入目前放入的最短的子序列即可采用离散化+优先队列实现时间复杂度O(N∗logN)O(N* \log N)O(N∗logN)Codeclass Solution {public: int mp[3*10007]; priority_queue<int,vector<int>,greater<int> >q[3*10007]; bool原创 2020-12-05 10:30:25 · 161 阅读 · 0 评论 -
Codeforces 1455C. Ping-pong(博弈)
DescriptionExampleinput31 12 11 7output0 11 10 7Solution两人轮流打乒乓球,因为存在放弃接球和上轮胜者必须发球的设定,所以后手占有主导权。题目要求每人的决策得先满足自己的胜场最多,对手的胜场最少的最优性。后手若一直让球直到对方最后一个球发出来时再开始接球,则能满足自己胜场最多,对方胜场最少而先手因为要先发球,所以本质上完全被后手所主导,自己毫无决策空间因此,先手只能先连赢x-1场后,后手开始连赢y场,然后游戏结束Cod原创 2020-12-02 23:17:31 · 1376 阅读 · 9 评论 -
Codeforces 1455B. Jumps(思维)
DescriptionExampleinput512345output13234Solution可以发现若每次操作都跳i的距离,最终的距离是等差数列之和;而显然我们不想让-1的操作次数过多,所以尽量先以等差数列跳到第一次 >= x 的位置,设为p若p == x,则直接出答案,若p > x, 则考虑将之前的若干次跳跃修改为-1操作,使得p -= (p - x)每修改一次操作 i 为 -1 对答案的贡献为 -(i+1),我们发现贡献是从-2开始连续的,并且只需原创 2020-12-02 23:08:43 · 274 阅读 · 0 评论 -
Codeforces 1455A. Strange Functions(思维)
DescriptionExampleinput5437998244353100000000712345678901337426966631415output1291026Solutiong(x)的分母部分就是将x的后缀0去掉(若存在)设x位数为k,若x有后缀0,g(x)的结果为k位最小值(100…),否则为1所以对于x的不同取值下,相同位数的x贡献为1(因为g(x)=1的情况与1位下的贡献重复),因此答案就为n的位数Code#include <bits/std原创 2020-12-02 22:59:46 · 259 阅读 · 0 评论 -
Codeforces 1457D. XOR-gun(二进制+思维)
DescriptionSolution设原始数组为aaa, 设bib_ibi 为aia_iai 的二进制位数若存在一个 iii,满足 bi−1=bi=bi+1b_{i-1} = b_{i} = b_{i+1}bi−1=bi=bi+1,则我们只需要将后两个数异或,得到的数一定比 ai−1a_{i-1}ai−1小(因为最高位变成0了)若这样的 iii 不存在,则原始数组的长度一定不超过 2*30 = 60,我们暴力计算 n≤60n \leq 60n≤60 的情况:最后的答案数组一定存在两原创 2020-11-30 21:54:45 · 221 阅读 · 0 评论 -
Codeforces 1457C. Bouncing Ball(DP)
DescriptionSolution先用dp预处理出以i为起点,以k为步长的路上会踩到几个砖块,以及有多少个格子然后枚举起点,更新答案Code#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e5 + 7;int dp[maxn];int num[maxn];int a[maxn];void init(int n) { for(int i = 1原创 2020-11-30 21:43:43 · 182 阅读 · 0 评论 -
LeetCode 767. 重构字符串(思维+构造)
题目链接DescriptionSolution先将S串中出现的不同字母计数,设出现次数最多的字母出现了x次容易发现当x - 1 > S.size() - x 时,不存在答案;其他情况下答案一定存在考虑特殊构造:我们开辟一个列数为x的矩阵,按照字母出现次数顺序依次一行行填入因为是按照字母出现次数从大到小的顺序填字母,所以必然不可能存在同一种字母在列中相邻(1)最后按照列从小到大的顺序依次将每列的字母按照行从小到大的顺序放入答案中因为(1)的性质存在,所以答案字符串中一定不存在相邻两个字原创 2020-11-30 20:39:44 · 109 阅读 · 0 评论 -
2020 ICPC Asia Taipei-Hsinchu Site H. Optimization for UltraNet(二分+最小生成树)
DescriptionSolution首先意识到这是一个最小生成树问题,但需要先满足所选边权值最小值最大,所以我们可以二分这个最小值,再用kruskal来check是否能成树然而最后需要计算任意两点路径上最小边权的和,貌似可以暴力水过去Code#include <bits/stdc++.h>using namespace std;#define pb push_backtypedef long long ll;const ll inf=1e18+10;const int m原创 2020-11-25 21:35:28 · 498 阅读 · 3 评论 -
2020 ICPC Asia Taipei-Hsinchu Site A.Right-Coupled Numbers(数学)
DescriptionSolution质因数分解Codeint main(int argc, char const *argv[]){ int T;scanf("%d",&T); while(T--) { int x;scanf("%d",&x); bool flag = false; for(int i = 1;i * i <= x;++i) { if(x % i == 0) { int a = i, b = x / i; if(b原创 2020-11-25 21:27:42 · 345 阅读 · 0 评论 -
Codeforces 1454D. Number into Sequence(思维+数学)
DescriptionExampleinput4236049999999374998207083output1232 2 901499999993714998207083Solution显然答案为分解质因数后个数最多的那个质因数的个数,设为k构造成k-1个该因子+1个剩下的数Codemap<ll,int>fac;ll solve(ll n) { ll mx = 0, cnt = 0; fac.clear(); for(ll i = 2;i *原创 2020-11-25 21:16:44 · 369 阅读 · 0 评论 -
Codeforces 1451C. String Equality(思维)
DecriptionExampleinput43 3abcbcd4 2abbaazza2 1zzaa6 2aaabbaddddccoutputNoYesNoYesSolution注意到操作1本质上就是对字符串的任意重排,说明位置不需要考虑操作2是不可逆的,即a->b 后无法实现b->a,我们记录下每个字母的个数顺序递推过去即可Codeconst int maxn = 2e6 + 10;char a[maxn],b[maxn];int num原创 2020-11-25 12:20:54 · 209 阅读 · 0 评论 -
Codeforces 1451B. Non-Substring Subsequence(思维+前缀和)
DescriptionExampleinput26 30010002 41 33 54 211111 42 3outputYESNOYESNOYESSolution如果能找到,必然可以是当前子串丢掉某一段点的子串+另一个点,我们用前缀和判断即可Code#include <bits/stdc++.h>using namespace std;const int maxn = 4e5 + 10;int bit[maxn];int pre[maxn]原创 2020-11-25 12:12:22 · 179 阅读 · 0 评论 -
Codeforces 1451A. Subtract or Divide(思维)
DescriptionExampleinput6123469output012223Solution奇偶讨论Code#include <bits/stdc++.h>using namespace std;typedef long long ll;int main(int argc, char const *argv[]){ int T;scanf("%d",&T); while(T--) { int n;scanf("%d",&原创 2020-11-25 12:02:36 · 147 阅读 · 0 评论 -
LeetCode 452. 用最少数量的箭引爆气球(贪心)
题目链接Solution按右端点排序后贪心的取右端点Codeclass Solution {public: bool vis[10010]; struct node{ int l,r; inline bool operator < (const node&it) const{ return r < it.r; } }num[10010]; int findMinArrowSh原创 2020-11-24 22:39:51 · 82 阅读 · 0 评论 -
2018 BACS Regional Programming Contest A. Criminal(打表)
DescriptionSolution暴力打表找规律Codeinline int bit(ll x) { int num = 0; while(x) { num++; x/=2; }return num;}ll solve(ll N,ll x) { ll tmp = x; if(x > N) return N; if(N == 1) return 1; if(x%2==0){return x-1;} x = (x + 1) / 2; ll num1 = bit(原创 2020-11-20 22:20:26 · 119 阅读 · 0 评论 -
2020ICPC 江西省赛 B. Apple(思维)
DescriptionSolution显然M个人先分别拿1 ~ M个,若不够N个就只需要给某个人加上凑够即可,但若N < (1+M)*M/2则一定是noCodeint main(int argc, char const *argv[]){ int T;scanf("%d",&T); while(T--) { int n,m;scanf("%d %d",&n,&m); ll mi = 1ll * (1+m) * m / 2; if(n < mi)原创 2020-11-20 00:31:43 · 274 阅读 · 0 评论 -
2020ICPC 江西省赛 K. Travel Expense(最短路+二分)
DescriptionHuanhuan is always working on fansy programming questions. However, today he decided to give himself a break and travel to a beautiful country. Therefore, another problem arose.There are totally n cities in the country. There are m two-way roa原创 2020-11-20 00:25:41 · 285 阅读 · 0 评论 -
LeetCode 1248. 统计「优美子数组」(暴力)
Description题目链接Solution存下奇数数字的下标,暴力即可Codeclass Solution {public: vector<int>id; int numberOfSubarrays(vector<int>& nums, int k) { int n = nums.size(); for(int i = 0;i < n;++i) { if(nums[i]&1)原创 2020-11-19 14:44:24 · 79 阅读 · 0 评论 -
2018 BACS Regional Programming Contest L. School Reunion(双指针)
DescriptionSolution注意到答案区间两端一定都在给定的2*n个端点上,所以我们可以根据单调性移动双指针即可Codeconst int inf=1e9+10;struct node{ int id, op; //0 st 1 ed}a[maxn];bool cmp(node x, node y) {return x.id < y.id;}int main(int argc, char const *argv[]){ int t,n,p; scanf ("%d原创 2020-11-17 20:01:25 · 152 阅读 · 0 评论