Personal records for practice of data structure and algorithm.
This file serves as a catalog for this repository.
别超数据范围
铺地毯问题
每次得到地毯后对矩形区域进行赋值会产生大量冗余操作
不如先得到所有地毯编号,然后对查询点,遍历地毯,得到最后的地毯编号
正方形内生产螺旋矩阵
一次做完一行/列
生活大爆炸石头剪刀布
- 两人各自规律性出拳,赢了加1分,其余不得分
没啥好说的,打表枚举就完事
——避免大量重复计算
- 一维: 顺着加就完事了
- 二维:sum[i][j] = sum[i-1][j] + sum[i][j-1] + a[i][j] - sum[i-1][j-1]
- i,j从1开始,矩阵sum[0][j]和sum[i][0]初始化为0
- 一维:顺着减
- 二维:a[i][j] = sum[i][j] -sum[i-1][j] - sum[i][j-1] +sum[i-1][j-1]
- n*n个数,求(x1,y1)到(x2,y2)矩形区域的和(x1<x2,y1<y2)
- 容斥原理的进一步应用
- 对某区间内数字加一个数,有多次这样的操作,求该数组最终的状态
- 标记数组,mark[l] += num,mark[r+1] -= num,求mark数组的和数组后,加到原数组上
- 上述情况的二维情形?
- 定义:对(x1, y1), (x2, y2)为对角顶点的矩阵加数,有多次这样的操作,求最终的矩阵
- 分析:对于和数组,对原矩阵的某顶点加数,相当于对和矩阵从某顶点开始无限向右下延申的所有顶点加数
- 则:mark[x1][y1] += num, mark[x2+1][y2+1] -= num, mark[x2+1][y1] -= num,mark[x1][y2+1] -= num
????看不懂看不懂
/* 总体思路:对于每张地毯,有:
carpet[x1][y1]+=1,carpet[x2+1][y2+1]+=1,carpet[x1][y2+1]-=1,carpet[x2+1][y1]-=1
对地毯矩阵求和,即可得到每个格子实际覆盖的地毯数目:
sum[i][j]=carpet[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]
输出即可
*/
——一种高效的枚举连续区间
的方法,通用思路为:
- 双指针
标记目标区间
,每当符合要求时,记录
当前状态,继续滑动窗口 - 如果是一开始就符合要求的呢?应一次性计算完区间内所有符合要求的区间,等下一次符合要求时,继续该操作
/* lr从0开始染色,mark(01)数组标记染色,和为操作数
区间长度小于k则r继续右移,碰到白的就记录,统计白的个数——即寻求长度为k的区间内,白色最少的数目
一旦区间长度==k,记录当前白色数是否最小,l右移至白色——其余区间白色数一定相同
r继续右移至长度等于k...l右移至下一个白色...r右移至...
*/
...先设计再写代码真爽
二分的本质:某个区间内猜可能的答案
,用猜的答案反向验证
该答案是否正确
- 更牛逼的暴力枚举
应用场景?答案在某区间内的都可以猜
- 可以把O(n)优化到O(logn)
- note:
定义区间
很重要,[]闭区间还是[)左开右闭,需要遍历完毕整个区间 - 应用:猜一个解判断是否可行:最小化最大值/最大化最小值....
/* solution:
答案区间[1,n],假设ans为最长最短距离,要求当前石头到下一块石头间距离>=ans,
否则移走后面的石头,计数+1
若移走的石头大于M,则ans大了;小于M则有可能为答案,记录;当l>r,区间内再无可能的答案,退出
更新区间
*/
似乎有些bug,但问题不大
/* 吃的速度可能为:[1,max(piles)]或[1,10^9]
反向验证得到耗时,比较耗时:
若time>h,则吃得太慢了,l=mid+1;若time<=h,则有可能为答案,更新final_k,r=mid-1
*/
——不绝对最优,但至少不差
涉及到优先队列,日后再说
——不能用int,得换long long
/* solution:先排个序,永远跳到落差最大的石头上 */
/* 老鼠吃奶酪
1 1 3 4 vs.
4 4 1 1
第一只老鼠吃掉其中的k块,求得分最大
二者相减得:
-3 -3 2 3,小于0则应第二只老鼠吃,否则第一只老鼠吃
那么问题转化为:让第一只老鼠吃掉此数组中最大的k个奶酪,在k=2时,为3,4;第二只老鼠吃:4,4
则吃的方案为:
第二只老鼠吃完;第一只老鼠吃相对于它的差值的前k个
*/
划分同类子问题
,生成递归树,寻找边界条件
- 一种思路:小样例推导递归代码
?
/* 指针一:指向prev node,指针二:需当前需要反转指向的node,指针三:指向下一个node
2->1,1=2,2=3, 3->4,什么时候终止?2==nullptr
*/
head永远指向头,next指向需要反转的node:
- next != nullptr时:
- head->next = next; next = next->next; head = next
over
先统计一共有多少个结点,再找到固定位置即可
/* 法1:哈希表 */
/* 法2:快慢指针法
note 1:有循环的话,不断next下去永远结束不了
note 2:如果两个指针的相对速度为1,那么在有循环的情况下,二者终将相遇
note 3:发现一个nullptr就不干了!
*/
然后就是一定的数学公式推导...推一下
?pass
常用于匹配;常用数组模拟栈
- 匹配类问题需要注意:递归地匹配,注意栈空时终止本轮匹配
其他先pass
大多基于递归,注意处理空树
分为自顶向下
和自下而上
遍历,自上而下更适用于无需更改树的结构的情形,而自下而上则适用于需要更改树的结构的情形
自顶向下
遍历
/* 检查根部是否相等,不相等直接返回false
注意空树
相等则比较左的左vs右的右--左的右vs右的左
*/
自下而上
遍历
层层上传
:很容易忽略一种情形——遍历到答案层就不该继续往下了
- 先进行思路设计,再写代码...不然简单题都能坑死你
- 带空格的字符串输入要用
getline(cin, str)
,单纯cin会被空格中止
- 不区分大小写——先统一转换为小写