矩阵中的矩形
统计子矩阵个数
满足单调性,用双指针优化。
最大矩形
满足单调性,且满足可合并性。故可进一步用单调栈优化,但当它求个数时,亦要
O
(
n
3
)
O(n^3)
O(n3)
DP
区间dp
扰乱字符串
一道很有意义的区间DP,一般而言,一维区间dp是在一个数组上做的,时间复杂度为
O
(
n
3
)
O(n^3)
O(n3),而这个二维dp是在两个数组上做的,时间复杂度为
O
(
n
4
)
O(n^4)
O(n4)。
1690. 石子游戏 VII
先手必胜需要证明。
1039. 多边形三角剖分的最低得分
线性dp
线性dp可以有多维,以三维为例显著特点
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]只会与
i
,
j
,
k
i,j,k
i,j,k规模减1的问题有关,这里每个变量可有两个选择,组合起来最多有六个。
二维线性dp
剑指 Offer II 097. 子序列的数目
字符串子串个数dp
典型特征,
f
[
i
]
[
c
h
]
=
s
u
m
(
f
[
i
−
1
]
[
a
−
z
]
)
f[i][ch]=sum(f[i-1][a-z])
f[i][ch]=sum(f[i−1][a−z]),因而可以进行优化,将复杂度从
26
n
26n
26n降到
26
+
n
26+n
26+n
940. 不同的子序列 II
1235. 规划兼职工作
逆推dp
对字母串可执行的最大删除数
对于这一类问题,思考的时候从前往后,dp的时候从后往前。
n
2
n^2
n2时间预处理出lcp,可
用后缀数组优化但没必要,
f
[
i
]
f[i]
f[i]表示
s
[
i
:
n
−
1
]
s[i:n-1]
s[i:n−1]所需的最大步数。
174. 地下城游戏
该问题如果正向思考,反向思考则能打开思路。
1406. 石子游戏 III
f
[
i
]
=
m
a
x
(
f
[
i
]
,
s
u
m
−
f
[
j
]
)
;
f
[
i
]
表示从
s
t
o
n
e
s
[
i
:
n
]
的石头先手最优能拿的数量
f[i]=max(f[i],sum-f[j]);f[i]表示从stones[i:n]的石头先手最优能拿的数量
f[i]=max(f[i],sum−f[j]);f[i]表示从stones[i:n]的石头先手最优能拿的数量
1140. 石子游戏 II
注意:题目中的M是变大后不会再变小的
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示从i到结尾,
M
=
j
M=j
M=j的最优解。
数位dp
面试题 17.06. 2出现的次数
通用模板
class Solution {
public:
int calc(int n,int x){
int L,M,R=0;
int res=0;
long long P=1;
while(n){
L = n/10;
M = n%10;
if(x==0){
if(x==M){
if(L)res+=(L-1)*P+R+1;
}else res+=L*P;
}else{
if(x>M)res+=L*P;
else if(x==M)res+=L*P+R+1;
else res+=(L+1)*P;
}
n/=10;
R=R+M*P;
P*=10;
}
return res;
}
int numberOf2sInRange(int n) {
return calc(n,2);
}
};
902. 最大为 N 的数字组合
注意将不足N位的单独计算,方便枚举
区间dp
换元dp
f[i][j] 的最优解为可为其它子问题表示的最优解
1563. 石子游戏 V
状压dp
1064. 小国王
预处理出合法状态和合法转移状态。
差分dp
f
[
i
]
[
j
]
=
k
f[i][j]=k
f[i][j]=k,差值为
j
j
j,两个板中较短一个的最大长度为
k
k
k。
956. 最高的广告牌
半满足性题目
寻找旋转排序数组中的最小值 II
链内单调递增,链外单调递减。
摩尔排序
贪心
11. 盛最多水的容器
证明:
双指针,优先移动短的那边。
令
l
为左边界,
r
为右边界,则
l
m
a
x
>
=
l
,
r
m
a
x
<
=
r
。
{
c
a
s
e
1
:
l
=
l
m
a
x
,
r
=
r
m
a
x
已经找到最大值
c
a
s
e
2
:
l
<
l
m
a
x
,
r
=
r
m
a
x
此时移动
l
,
h
[
l
]
<
h
[
r
]
c
a
s
e
3
:
l
=
l
m
a
x
,
r
<
r
m
a
x
此时移动
r
,
h
[
r
]
<
h
[
l
]
c
a
s
e
4
:
l
>
l
m
a
x
,
r
>
r
m
a
x
此时既可移动
l
,
也可移动
r
,但我们选择高度较低的一个
双指针,优先移动短的那边。\\ 令l为左边界,r为右边界,则lmax>=l,rmax<=r。\\ \begin{cases} case1:l=lmax,r=rmax& 已经找到最大值\\ case2:l<lmax,r=rmax& 此时移动l,h[l]<h[r]\\ case3:l=lmax,r<rmax&此时移动r, h[r]<h[l]\\ case4:l>lmax,r>rmax& 此时既可移动l,也可移动r,但我们选择高度较低的一个\\ \end{cases}
双指针,优先移动短的那边。令l为左边界,r为右边界,则lmax>=l,rmax<=r。⎩
⎨
⎧case1:l=lmax,r=rmaxcase2:l<lmax,r=rmaxcase3:l=lmax,r<rmaxcase4:l>lmax,r>rmax已经找到最大值此时移动l,h[l]<h[r]此时移动r,h[r]<h[l]此时既可移动l,也可移动r,但我们选择高度较低的一个
选择高度较低的偏移一定能得到正确结果。
45. 跳跃游戏 II
证明:
令
l
=
0
,
r
=
0
。
则可计算从
l
−
r
的点可以辐射到的新的范围,其中
l
=
r
+
1
,
r
=
最远距离。每一轮均选择可以辐射最远的点
.
假设最优解没有选择可以辐射最远的点,那么选择辐射最远的点不会使结果变差。
令l=0,r=0。\\ 则可计算从l-r的点可以辐射到的新的范围,其中l=r+1,r=最远距离。 每一轮均选择可以辐射最远的点.\\ 假设最优解没有选择可以辐射最远的点,那么选择辐射最远的点不会使结果变差。
令l=0,r=0。则可计算从l−r的点可以辐射到的新的范围,其中l=r+1,r=最远距离。每一轮均选择可以辐射最远的点.假设最优解没有选择可以辐射最远的点,那么选择辐射最远的点不会使结果变差。
179. 最大数
证明:
将数字转化为字符串,按如下规则
s
t
r
a
+
s
t
r
b
>
s
t
r
b
+
s
t
r
a
。
假设最优解中存在一个
s
t
r
a
+
s
t
r
b
>
s
t
r
b
+
s
t
r
a
,且
s
t
r
a
在后,
s
t
r
b
在前,则能找
到一个更优解是将这两个子串交换。故最优解中不存在违反上述规则的情况。
将数字转化为字符串,按如下规则 stra+strb>strb+stra。\\ 假设最优解中存在一个stra+strb>strb+stra,且stra在后,strb在前,则能找\\到一个更优解是将这两个子串交换。故最优解中不存在违反上述规则的情况。
将数字转化为字符串,按如下规则stra+strb>strb+stra。假设最优解中存在一个stra+strb>strb+stra,且stra在后,strb在前,则能找到一个更优解是将这两个子串交换。故最优解中不存在违反上述规则的情况。
397. 整数替换
对于
x
x
x
x
x
01
结尾的,假设前面无
1
,则为结果,否则,选择减
1
优于加
1
。
对于
x
x
x
x
x
11
结尾的,假设前面无
1
,则差两步,前面有
1
,选择加
1
优于选择减
1
。
对于xxxxx01结尾的,假设前面无1,则为结果,否则,选择减1优于加1。\\ 对于xxxxx11结尾的,假设前面无1,则差两步,前面有1,选择加1优于选择减1。\\
对于xxxxx01结尾的,假设前面无1,则为结果,否则,选择减1优于加1。对于xxxxx11结尾的,假设前面无1,则差两步,前面有1,选择加1优于选择减1。
502. IPO
首先用需要资本排序。
可用资本是递增的,用堆维护当前所有可用资本,优先完成利润最大的。
首先用需要资本排序。\\ 可用资本是递增的,用堆维护当前所有可用资本,优先完成利润最大的。\\
首先用需要资本排序。可用资本是递增的,用堆维护当前所有可用资本,优先完成利润最大的。
517. 超级洗衣机
1.
选定一个洗衣机,它要移动的次数为左右两边需要它移动的次数。
1.选定一个洗衣机,它要移动的次数为左右两边需要它移动的次数。
1.选定一个洗衣机,它要移动的次数为左右两边需要它移动的次数。
1686. 石子游戏 VI
贪心策略,和从大到小排序。
反证明,假设最优解不是按如上顺序拿的,则必然存在一个更优解。
情况一:取数顺序虽不是如上,但最终取的系列与贪心策略相同,该情况无须讨论
情况二:取数顺序不同,存在一个
a
[
i
]
+
b
[
i
]
<
a
[
j
]
+
b
[
j
]
,
其中
i
<
j
且
i
被
a
l
i
c
e
取,
j
被
b
o
b
取,则交换两项有:
s
u
m
A
l
i
c
e
=
s
u
m
A
l
i
c
e
−
(
a
[
i
]
−
a
[
j
]
)
,
s
u
m
B
o
b
=
s
u
m
b
o
b
−
(
b
[
j
]
−
b
[
i
]
)
;
这种情况下,
A
l
i
c
e
和
B
o
b
之间的分差会被拉大。显然是一个更好的解。
贪心策略,和从大到小排序。\\ 反证明,假设最优解不是按如上顺序拿的,则必然存在一个更优解。\\ 情况一:取数顺序虽不是如上,但最终取的系列与贪心策略相同,该情况无须讨论\\ 情况二:取数顺序不同,存在一个a[i]+b[i]<a[j]+b[j],其中i<j且i被 alice取,j被bob取,则交换两项有:\\ sumAlice=sumAlice-(a[i]-a[j]),sumBob=sumbob-(b[j]-b[i]);\\ 这种情况下,Alice和Bob之间的分差会被拉大。显然是一个更好的解。
贪心策略,和从大到小排序。反证明,假设最优解不是按如上顺序拿的,则必然存在一个更优解。情况一:取数顺序虽不是如上,但最终取的系列与贪心策略相同,该情况无须讨论情况二:取数顺序不同,存在一个a[i]+b[i]<a[j]+b[j],其中i<j且i被alice取,j被bob取,则交换两项有:sumAlice=sumAlice−(a[i]−a[j]),sumBob=sumbob−(b[j]−b[i]);这种情况下,Alice和Bob之间的分差会被拉大。显然是一个更好的解。
后缀数组
1044. 最长重复子串
数学题
877. 石子游戏
∣
A
∣
B
∣
A
∣
B
∣
A
∣
B
∣
要求长度为偶数,先手可保证拿
A
序列还是
B
序列,而这其中必有一个大于另外一个
|A|B|A|B|A|B|\\ 要求长度为偶数,先手可保证拿A序列还是B序列,而这其中必有一个大于另外一个
∣A∣B∣A∣B∣A∣B∣要求长度为偶数,先手可保证拿A序列还是B序列,而这其中必有一个大于另外一个
2029. 石子游戏 IX
首先这是无平局的游戏,那么只要先手无法找到必胜策略,则其必败。分类讨论。
6222. 美丽整数的最小增量
会就是会,不会就是不会,一定是产生进位的时候才会减小。
双指针
双指针分为两种,一种是从两端向中间集中,一种是从左往右。
-
向中间集中,一定要满足结果只在 [ l , r − 1 ] 或 [ l + 1 , r ] [l,r-1]或[l+1,r] [l,r−1]或[l+1,r]中。
11. 盛最多水的容器
本题思想是贪心,满足第一类双指针。
16. 最接近的三数之和 -
从左往右要满足, r ′ > r , 则 l ′ > = l r'>r,则l'>=l r′>r,则l′>=l。即当r单调时,l也单调。
2444. 统计定界子数组的数目
该题在局部上满足第二类双指针。
并查集
LCP 71. 集水器
在左下右围上一圈0,将每个正方形分成四块,给每个小三角形一个编号,从下往上,如果不能将小三角形与0连通,则这一点可以有水
在上下右右围上一圈0,如果小三角形能到达0,则表示小三角形不封闭,可以有水进来
剑指 Offer II 111. 计算除法
带权并查集
运算hack
搜索
深搜
宽搜
图论
2242. 节点序列的最大得分
这是一道很经典的题目,直接枚举复杂度很高,选择从中间那条边枚举另外两个端点,但这样复杂度依然会很高,可以只取左右最大的两个点即可。
dfs+二叉树+树链剖分思想
一个节点被删去后的高度
=
兄弟节点对应的高度,祖先节点被删的高度的最大值
一个节点被删去后的高度=兄弟节点对应的高度,祖先节点被删的高度的最大值
一个节点被删去后的高度=兄弟节点对应的高度,祖先节点被删的高度的最大值
6223. 移除子树后的二叉树高度
单调栈
以从左往右为例
- 求离它最近的比它小的或比它大的值的位置.
用单调栈直接维护,要求当前元素向左延申的单调栈 - 求离它最远的比它小的或比它大的值的位置.
求必须包含左端点的单调栈。
本题的做法是单调栈+动态规划
907. 子数组的最小值之和
组合数据结构
摩尔投票法
class Solution {
public:
int moreThanHalfNum_Solution(vector<int>& nums) {
int n=nums.size();
int t=nums[0];
int cnt=1;
for (int i = 1; i < n; i ++ ){
if(nums[i]==t)cnt++;
else{
cnt--;
if(cnt==0){
t=nums[i];
cnt=1;
}
}
}
return t;
}
};
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> ans;
int r1,r2,c1=0,c2=0;
for(auto i:nums){
if(c1&&r1==i)c1++;
else if(c2&&r2==i)c2++;
else if(!c1)r1=i,c1=1;
else if(!c2)r2=i,c2=1;
else c1--,c2--;
}
c1=0,c2=0;
for(auto i:nums){
if(i==r1)c1++;
else if(i==r2)c2++;
}
if(c1>nums.size()/3)ans.push_back(r1);
if(c2>nums.size()/3)ans.push_back(r2);
return ans;
}
};
BFS
BFS+set
注意,C++ 的set类型自带lower_bound,不要用std::lower_bound库函数。
6365. 最少翻转操作数