# 字节跳动的算法面试题是什么难度?
# 字节跳动的算法面试题是什么难度?
由于 lucifer 我是一个小前端, 最近也在准备写一个《前端如何搞定算法面试》的专栏,因此最近没少看各大公司的面试题。都说字节跳动算法题比较难,我就先拿 ta 下手,做了几套 。这次我们就拿一套 `2018 年的前端校招(第四批)`来看下字节的算法笔试题的难度几何。地址:<https://www.nowcoder.com/test/8536639/summary>
> 实际上,这套字节的前端岗位笔试题和后端以及算法岗位的笔试题也只有一道题目(红包的设计题被换成了另外一个设计题)不一样而已,因此也不需要担心你不是前端,题目类型和难度和你的岗位不匹配。
这套题一共四道题, 两道问答题, 两道编程题。
其中一道问答题是 LeetCode 426 的原题,只不过题型变成了找茬(改错)。可惜的是 LeetCode 的 426 题是一个会员题目,没有会员的就看不来了。不过,剑指 Offer 正好也有这个题,并且力扣将剑指 Offer 全部的题目都 OJ 化了。 这道题大家可以去 <https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof> 提交答案。简单说一下这个题目的思路,我们只需要中序遍历即可得到一个有序的数列,同时在中序遍历过程中将 pre 和 cur 节点通过指针串起来即可。
另一个问答是红包题目,这里不多说了。我们重点看一下剩下两个算法编程题。
![](https://img.kancloud.cn/05/86/0586e3f19c229575cf50b4342797cd8e_1381x1080.jpg)
> 两个问答题由于不能在线判题,我没有做,只做了剩下两个编程题。
## 球队比赛
第一个编程题是一个球队比赛的题目。
### 题目描述
有三只球队,每只球队编号分别为球队 1,球队 2,球队 3,这三只球队一共需要进行 n 场比赛。现在已经踢完了 k 场比赛,每场比赛不能打平,踢赢一场比赛得一分,输了不得分不减分。已知球队 1 和球队 2 的比分相差 d1 分,球队 2 和球队 3 的比分相差 d2 分,每场比赛可以任意选择两只队伍进行。求如果打完最后的 (n-k) 场比赛,有没有可能三只球队的分数打平。
### 思路
假设球队 1,球队 2,球队 3 此时的胜利次数分别为 a,b,c,球队 1,球队 2,球队 3 总的胜利次数分别为 n1,n2,n3。
我一开始的想法是只要保证 n1,n2,n3 相等且都小于等于 n / 3 即可。如果题目给了 n1,n2,n3 的值就直接:
```
<pre class="calibre18">```
print(n1 == n2 == n3 == n / 3)
```
```
可是不仅 n1,n2,n3 没给, a,b,c 也没有给。
实际上此时我们的信息仅仅是:
```
<pre class="calibre18">```
① a + b + c = k
② a - b = d1 or b - a = d1
③ b - c = d2 or c - b = d2
```
```
其中 k 和 d1,d2 是已知的。a ,b,c 是未知的。 也就是说我们需要枚举所有的 a,b,c 可能性,解方程求出合法的 a,b,c,并且 合法的 a,b,c 都小于等于 n / 3 即可。
> 这个 a,b,c 的求解数学方程就是中学数学难度, 三个等式化简一下即可,具体见下方代码区域。
- a 只需要再次赢得 n / 3 - a 次
- b 只需要再次赢得 n / 3 - b 次
- c 只需要再次赢得 n / 3 - c 次
```
<pre class="calibre18">```
n1 = a + n / 3 - a = n / 3
n2 = b + (n / 3 - b) = n / 3
n3 = c + (n / 3 - c) = n / 3
```
```
### 代码(Python)
> 牛客有点让人不爽, 需要 print 而不是 return
```
<pre class="calibre18">```
t = int(input())
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(t):
n, k, d1, d2 = map(int, input().split(<span class="hljs-string">" "</span>))
<span class="hljs-keyword">if</span> n % <span class="hljs-params">3</span> != <span class="hljs-params">0</span>:
print(<span class="hljs-string">'no'</span>)
<span class="hljs-keyword">continue</span>
abcs = []
<span class="hljs-keyword">for</span> r1 <span class="hljs-keyword">in</span> [<span class="hljs-params">-1</span>, <span class="hljs-params">1</span>]:
<span class="hljs-keyword">for</span> r2 <span class="hljs-keyword">in</span> [<span class="hljs-params">-1</span>, <span class="hljs-params">1</span>]:
a = (k + <span class="hljs-params">2</span> * r1 * d1 + r2 * d2) / <span class="hljs-params">3</span>
b = (k + <span class="hljs-params">-1</span> * r1 * d1 + r2 * d2) / <span class="hljs-params">3</span>
c = (k + <span class="hljs-params">-1</span> * r1 * d1 + <span class="hljs-params">-2</span> * r2 * d2) / <span class="hljs-params">3</span>
a + r1
<span class="hljs-keyword">if</span> <span class="hljs-params">0</span> <= a <= k <span class="hljs-keyword">and</span> <span class="hljs-params">0</span> <= b <= k <span class="hljs-keyword">and</span> <span class="hljs-params">0</span> <= c <= k <span class="hljs-keyword">and</span> a.is_integer() <span class="hljs-keyword">and</span> b.is_integer() <span class="hljs-keyword">and</span> c.is_integer():
abcs.append([a, b, c])
flag = <span class="hljs-keyword">False</span>
<span class="hljs-keyword">for</span> abc <span class="hljs-keyword">in</span> abcs:
<span class="hljs-keyword">if</span> len(abc) > <span class="hljs-params">0</span> <span class="hljs-keyword">and</span> max(abc) <= n / <span class="hljs-params">3</span>:
flag = <span class="hljs-keyword">True</span>
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">if</span> flag:
print(<span class="hljs-string">'yes'</span>)
<span class="hljs-keyword">else</span>:
print(<span class="hljs-string">'no'</span>)
```
```
**复杂度分析**
- 时间复杂度:O(t)O(t)O(t)
- 空间复杂度:O(t)O(t)O(t)
### 小结
感觉这个难度也就是力扣中等水平吧,力扣也有一些数学等式转换的题目, 比如 [494.target-sum](https://github.com/azl397985856/leetcode/blob/master/problems/494.target-sum.md "494.target-sum")
## 转换字符串
### 题目描述
有一个仅包含’a’和’b’两种字符的字符串 s,长度为 n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限 m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。
### 思路
看完题我就有种似曾相识的感觉。
> 每次对妹子说出这句话的时候,她们都会觉得好假 ^\_^
不过这次是真的。 ”哦,不!每次都是真的“。 这道题其实就是我之前写的滑动窗口的一道题[【1004. 最大连续 1 的个数 III】滑动窗口(Python3)](https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/1004-zui-da-lian-xu-1de-ge-shu-iii-hua-dong-chuang/ "【1004. 最大连续 1 的个数 III】滑动窗口(Python3)")的换皮题。 专题地址:<https://github.com/azl397985856/leetcode/blob/master/thinkings/slide-window.md>
所以说,如果这道题你完全没有思路的话。说明:
- 抽象能力不够。
- 滑动窗口问题理解不到位。
第二个问题可以看我上面贴的地址,仔细读读,并完成课后练习即可解决。
第一个问题就比较困难了, 不过多看我的题解也可以慢慢提升的。比如:
- [《割绳子》](https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/ "《割绳子》") 实际上就是 [343. 整数拆分](https://lucifer.ren/blog/2020/05/16/343.integer-break/ "343. 整数拆分") 的换皮题。
- 力扣 230 和 力扣 645 就是换皮题,详情参考[位运算专题](https://lucifer.ren/blog/2020/03/24/bit/ "位运算专题")
- 以及 [你的衣服我扒了 - 《最长公共子序列》](https://lucifer.ren/blog/2020/07/01/LCS/)
- 以及 [穿上衣服我就不认识你了?来聊聊最长上升子序列](https://lucifer.ren/blog/2020/06/20/LIS/)
- 以及 [一招吃遍力扣四道题,妈妈再也不用担心我被套路啦~](https://lucifer.ren/blog/2020/06/13/%E5%88%A0%E9%99%A4%E9%97%AE%E9%A2%98/)
- 等等
回归这道题。其实我们只需要稍微抽象一下, 就是一个纯算法题。 抽象的另外一个好处则是将很多不同的题目返璞归真,从而可以在茫茫题海中逃脱。这也是我开启[《我是你的妈妈呀》](https://lucifer.ren/blog/2020/08/03/mother-01/) 的原因之一。
如果我们把 a 看成是 0 , b 看成是 1。或者将 b 看成 1, a 看成 0。不就抽象成了:
```
<pre class="calibre18">```
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 m 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
```
```
这就是 力扣 [1004. 最大连续 1 的个数 III](https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/1004-zui-da-lian-xu-1de-ge-shu-iii-hua-dong-chuang/) 原题。
因此实际上我们要求的是上面两种情况:
1. a 表示 0, b 表示 1
2. a 表示 1, b 表示 0
的较大值。
> lucifer 小提示: 其实我们也可以仅仅考虑一种情况,比如 a 看成是 0 , b 看成是 1。这个时候, 我们操作变成了两种情况,0 变成 1 或者 1 变成 0,同时求解的也变成了最长连续 0 或者 最长连续 1 。 由于这种抽象操作起来更麻烦, 我们不考虑。
问题得到了抽象就好解决了。我们只需要记录下加入窗口的是 0 还是 1:
- 如果是 1,我们什么都不用做
- 如果是 0,我们将 m 减 1
相应地,我们需要记录移除窗口的是 0 还是 1:
- 如果是 1,我们什么都不做
- 如果是 0,说明加进来的时候就是 1,加进来的时候我们 m 减去了 1,这个时候我们再加 1。
> lucifer 小提示: 实际上题目中是求**连续** a 或者 b 的长度。看到连续,大家也应该有滑动窗口的敏感度, 别管行不行, 想到总该有的。
我们拿 A = \[1, 1, 0, 1, 0, 1\], m = 1 来说。看下算法的具体过程:
> lucifer 小提示: 左侧的数字表示此时窗口大小,黄色格子表示修补的墙,黑色方框表示的是窗口。
![](https://img.kancloud.cn/62/36/6236deb5f14e162619f39ab1cdbca471_748x204.jpg)
这里我形象地将 0 看成是洞,1 看成是墙, 我们的目标就是补洞,使得连续的墙最长。
![](https://img.kancloud.cn/17/93/1793636fdfb815f98395bfd4e1b2ec95_668x184.jpg)
每次碰到一个洞,我们都去不加选择地修补。由于 m 等于 1, 也就是说我们最多补一个洞。因此需要在修补超过一个洞的时候,我们需要调整窗口范围,使得窗口内最多修补一个墙。由于窗口表示的就是连续的墙(已有的或者修补的),因此最终我们返回窗口的最大值即可。
![](https://img.kancloud.cn/d2/4b/d24b4d12a8ad9b51115e72a6f4ce2e4b_1202x490.jpg)
> 由于下面的图窗口内有两个洞,这和”最多补一个洞“冲突, 我们需要收缩窗口使得满足“最多补一个洞”的先决条件。
![](https://img.kancloud.cn/d3/15/d315f4969ae2b53f5f434e3e59d58422_870x406.jpg)
因此最大的窗口就是 max(2, 3, 4, ...) = 4。
> lucifer 小提示: 可以看出我们不加选择地修补了所有的洞,并调整窗口,使得窗口内最多有 m 个修补的洞,因此窗口的最大值就是答案。然而实际上,我们并不需要真的”修补“(0 变成 1),而是仅仅修改 m 的值即可。
我们先来看下抽象之后的**其中一种情况**的代码:
```
<pre class="calibre18">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">longestOnes</span><span class="hljs-params">(self, A: List[int], m: int)</span> -> int:</span>
i = <span class="hljs-params">0</span>
<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(len(A)):
m -= <span class="hljs-params">1</span> - A[j]
<span class="hljs-keyword">if</span> m < <span class="hljs-params">0</span>:
m += <span class="hljs-params">1</span> - A[i]
i += <span class="hljs-params">1</span>
<span class="hljs-keyword">return</span> j - i + <span class="hljs-params">1</span>
```
```
因此**完整代码**就是:
```
<pre class="calibre18">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">longestOnes</span><span class="hljs-params">(self, A: List[int], m: int)</span> -> int:</span>
i = <span class="hljs-params">0</span>
<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(len(A)):
m -= <span class="hljs-params">1</span> - A[j]
<span class="hljs-keyword">if</span> m < <span class="hljs-params">0</span>:
m += <span class="hljs-params">1</span> - A[i]
i += <span class="hljs-params">1</span>
<span class="hljs-keyword">return</span> j - i + <span class="hljs-params">1</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">longestAorB</span><span class="hljs-params">(self, A:List[int], m: int)</span> -> int:</span>
<span class="hljs-keyword">return</span> max(self.longestOnes(map(<span class="hljs-keyword">lambda</span> x: <span class="hljs-params">0</span> <span class="hljs-keyword">if</span> x == <span class="hljs-string">'a'</span> <span class="hljs-keyword">else</span> <span class="hljs-params">1</span>, A) ,m), self.longestOnes(map(<span class="hljs-keyword">lambda</span> x: <span class="hljs-params">1</span> <span class="hljs-keyword">if</span> x == <span class="hljs-string">'a'</span> <span class="hljs-keyword">else</span> <span class="hljs-params">0</span>, A),m))
```
```
这里的两个 map 会生成两个不同的数组。 我只是为了方便大家理解才新建的两个数组, 实际上根本不需要,具体见后面的代码.
### 代码(Python)
```
<pre class="calibre18">```
i = <span class="hljs-params">0</span>
n, m = map(int, input().split(<span class="hljs-string">" "</span>))
s = input()
ans = <span class="hljs-params">0</span>
k = m <span class="hljs-title"># 存一下,后面也要用这个初始值</span>
<span class="hljs-title"># 修补 b</span>
<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(n):
m -= ord(s[j]) - ord(<span class="hljs-string">'a'</span>)
<span class="hljs-keyword">if</span> m < <span class="hljs-params">0</span>:
m += ord(s[i]) - ord(<span class="hljs-string">'a'</span>)
i += <span class="hljs-params">1</span>
ans = j - i + <span class="hljs-params">1</span>
i = <span class="hljs-params">0</span>
<span class="hljs-title"># 修补 a</span>
<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(n):
k += ord(s[j]) - ord(<span class="hljs-string">'b'</span>)
<span class="hljs-keyword">if</span> k < <span class="hljs-params">0</span>:
k -= ord(s[i]) - ord(<span class="hljs-string">'b'</span>)
i += <span class="hljs-params">1</span>
print(max(ans, j - i + <span class="hljs-params">1</span>))
```
```
**复杂度分析**
- 时间复杂度:O(N)O(N)O(N)
- 空间复杂度:O(1)O(1)O(1)
### 小结
这道题就是一道换了皮的力扣题,难度中等。如果你能将问题抽象,同时又懂得滑动窗口,那这道题就很容易。我看了题解区的参考答案, 内容比较混乱,不够清晰。这也是我写下这篇文章的原因之一。
## 总结
这一套字节跳动的题目一共四道,一道设计题,三道算法题。
其中三道算法题从难度上来说,基本都是中等难度。从内容来看,基本都是力扣的换皮题。但是如果我不说他们是换皮题, 你们能发现么? 如果你可以的话,说明你的抽象能力已经略有小成了。如果看不出来也没有关系,关注我。 手把手扒皮给你们看,扒多了慢慢就会了。切记,不要盲目做题!如果你做了很多题, 这几道题还是看不出套路,说明你该缓缓,改变下刷题方式了。
更多题解可以访问我的 LeetCode 题解仓库:<https://github.com/azl397985856/leetcode> 。 目前已经 36K+ star 啦。
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
![](https://img.kancloud.cn/cf/0f/cf0fc0dd21e94b443dd8bca6cc15b34b_900x500.jpg)
- Introduction
- 第一章 - 算法专题
- 数据结构
- 基础算法
- 二叉树的遍历
- 动态规划
- 哈夫曼编码和游程编码
- 布隆过滤器
- 字符串问题
- 前缀树专题
- 《贪婪策略》专题
- 《深度优先遍历》专题
- 滑动窗口(思路 + 模板)
- 位运算
- 设计题
- 小岛问题
- 最大公约数
- 并查集
- 前缀和
- 平衡二叉树专题
- 第二章 - 91 天学算法
- 第一期讲义-二分法
- 第一期讲义-双指针
- 第二期
- 第三章 - 精选题解
- 《日程安排》专题
- 《构造二叉树》专题
- 字典序列删除
- 百度的算法面试题 * 祖玛游戏
- 西法的刷题秘籍】一次搞定前缀和
- 字节跳动的算法面试题是什么难度?
- 字节跳动的算法面试题是什么难度?(第二弹)
- 《我是你的妈妈呀》 * 第一期
- 一文带你看懂二叉树的序列化
- 穿上衣服我就不认识你了?来聊聊最长上升子序列
- 你的衣服我扒了 * 《最长公共子序列》
- 一文看懂《最大子序列和问题》
- 第四章 - 高频考题(简单)
- 面试题 17.12. BiNode
- 0001. 两数之和
- 0020. 有效的括号
- 0021. 合并两个有序链表
- 0026. 删除排序数组中的重复项
- 0053. 最大子序和
- 0088. 合并两个有序数组
- 0101. 对称二叉树
- 0104. 二叉树的最大深度
- 0108. 将有序数组转换为二叉搜索树
- 0121. 买卖股票的最佳时机
- 0122. 买卖股票的最佳时机 II
- 0125. 验证回文串
- 0136. 只出现一次的数字
- 0155. 最小栈
- 0167. 两数之和 II * 输入有序数组
- 0169. 多数元素
- 0172. 阶乘后的零
- 0190. 颠倒二进制位
- 0191. 位1的个数
- 0198. 打家劫舍
- 0203. 移除链表元素
- 0206. 反转链表
- 0219. 存在重复元素 II
- 0226. 翻转二叉树
- 0232. 用栈实现队列
- 0263. 丑数
- 0283. 移动零
- 0342. 4的幂
- 0349. 两个数组的交集
- 0371. 两整数之和
- 0437. 路径总和 III
- 0455. 分发饼干
- 0575. 分糖果
- 0874. 模拟行走机器人
- 1260. 二维网格迁移
- 1332. 删除回文子序列
- 第五章 - 高频考题(中等)
- 0002. 两数相加
- 0003. 无重复字符的最长子串
- 0005. 最长回文子串
- 0011. 盛最多水的容器
- 0015. 三数之和
- 0017. 电话号码的字母组合
- 0019. 删除链表的倒数第N个节点
- 0022. 括号生成
- 0024. 两两交换链表中的节点
- 0029. 两数相除
- 0031. 下一个排列
- 0033. 搜索旋转排序数组
- 0039. 组合总和
- 0040. 组合总和 II
- 0046. 全排列
- 0047. 全排列 II
- 0048. 旋转图像
- 0049. 字母异位词分组
- 0050. Pow(x, n)
- 0055. 跳跃游戏
- 0056. 合并区间
- 0060. 第k个排列
- 0062. 不同路径
- 0073. 矩阵置零
- 0075. 颜色分类
- 0078. 子集
- 0079. 单词搜索
- 0080. 删除排序数组中的重复项 II
- 0086. 分隔链表
- 0090. 子集 II
- 0091. 解码方法
- 0092. 反转链表 II
- 0094. 二叉树的中序遍历
- 0095. 不同的二叉搜索树 II
- 0096. 不同的二叉搜索树
- 0098. 验证二叉搜索树
- 0102. 二叉树的层序遍历
- 0103. 二叉树的锯齿形层次遍历
- 105. 从前序与中序遍历序列构造二叉树
- 0113. 路径总和 II
- 0129. 求根到叶子节点数字之和
- 0130. 被围绕的区域
- 0131. 分割回文串
- 0139. 单词拆分
- 0144. 二叉树的前序遍历
- 0150. 逆波兰表达式求值
- 0152. 乘积最大子数组
- 0199. 二叉树的右视图
- 0200. 岛屿数量
- 0201. 数字范围按位与
- 0208. 实现 Trie (前缀树)
- 0209. 长度最小的子数组
- 0211. 添加与搜索单词 * 数据结构设计
- 0215. 数组中的第K个最大元素
- 0221. 最大正方形
- 0229. 求众数 II
- 0230. 二叉搜索树中第K小的元素
- 0236. 二叉树的最近公共祖先
- 0238. 除自身以外数组的乘积
- 0240. 搜索二维矩阵 II
- 0279. 完全平方数
- 0309. 最佳买卖股票时机含冷冻期
- 0322. 零钱兑换
- 0328. 奇偶链表
- 0334. 递增的三元子序列
- 0337. 打家劫舍 III
- 0343. 整数拆分
- 0365. 水壶问题
- 0378. 有序矩阵中第K小的元素
- 0380. 常数时间插入、删除和获取随机元素
- 0416. 分割等和子集
- 0445. 两数相加 II
- 0454. 四数相加 II
- 0494. 目标和
- 0516. 最长回文子序列
- 0518. 零钱兑换 II
- 0547. 朋友圈
- 0560. 和为K的子数组
- 0609. 在系统中查找重复文件
- 0611. 有效三角形的个数
- 0718. 最长重复子数组
- 0754. 到达终点数字
- 0785. 判断二分图
- 0820. 单词的压缩编码
- 0875. 爱吃香蕉的珂珂
- 0877. 石子游戏
- 0886. 可能的二分法
- 0900. RLE 迭代器
- 0912. 排序数组
- 0935. 骑士拨号器
- 1011. 在 D 天内送达包裹的能力
- 1014. 最佳观光组合
- 1015. 可被 K 整除的最小整数
- 1019. 链表中的下一个更大节点
- 1020. 飞地的数量
- 1023. 驼峰式匹配
- 1031. 两个非重叠子数组的最大和
- 1104. 二叉树寻路
- 1131.绝对值表达式的最大值
- 1186. 删除一次得到子数组最大和
- 1218. 最长定差子序列
- 1227. 飞机座位分配概率
- 1261. 在受污染的二叉树中查找元素
- 1262. 可被三整除的最大和
- 1297. 子串的最大出现次数
- 1310. 子数组异或查询
- 1334. 阈值距离内邻居最少的城市
- 1371.每个元音包含偶数次的最长子字符串
- 第六章 - 高频考题(困难)
- 0004. 寻找两个正序数组的中位数
- 0023. 合并K个升序链表
- 0025. K 个一组翻转链表
- 0030. 串联所有单词的子串
- 0032. 最长有效括号
- 0042. 接雨水
- 0052. N皇后 II
- 0084. 柱状图中最大的矩形
- 0085. 最大矩形
- 0124. 二叉树中的最大路径和
- 0128. 最长连续序列
- 0145. 二叉树的后序遍历
- 0212. 单词搜索 II
- 0239. 滑动窗口最大值
- 0295. 数据流的中位数
- 0301. 删除无效的括号
- 0312. 戳气球
- 0335. 路径交叉
- 0460. LFU缓存
- 0472. 连接词
- 0488. 祖玛游戏
- 0493. 翻转对
- 0887. 鸡蛋掉落
- 0895. 最大频率栈
- 1032. 字符流
- 1168. 水资源分配优化
- 1449. 数位成本和为目标值的最大数字
- 后序