Skip to content

Commit bfb9839

Browse files
committed
Use Katex in solution markdown
1 parent 0ae1bb2 commit bfb9839

11 files changed

+96
-106
lines changed

leetcode/0125.Valid-Palindrome/125. Valid Palindrome.go

-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import (
55
)
66

77
func isPalindrome(s string) bool {
8-
98
s = strings.ToLower(s)
10-
119
i, j := 0, len(s)-1
1210
for i < j {
1311
for i < j && !isChar(s[i]) {
@@ -22,7 +20,6 @@ func isPalindrome(s string) bool {
2220
i++
2321
j--
2422
}
25-
2623
return true
2724
}
2825

leetcode/1203.Sort-Items-by-Groups-Respecting-Dependencies/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Return any solution if there is more than one solution and return an **empty li
1414

1515
**Example 1:**
1616

17-
![https://assets.leetcode.com/uploads/2019/09/11/1359_ex1.png](https://assets.leetcode.com/uploads/2019/09/11/1359_ex1.png)
17+
![](https://assets.leetcode.com/uploads/2019/09/11/1359_ex1.png)
1818

1919
```
2020
Input: n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3,6],[],[],[]]
@@ -56,11 +56,11 @@ Explanation: This is the same as example 1 except that 4 needs to be before 6 i
5656

5757
- 读完题能确定这一题是拓扑排序。但是和单纯的拓扑排序有区别的是,同一小组内的项目需要彼此相邻。用 2 次拓扑排序即可解决。第一次拓扑排序排出组间的顺序,第二次拓扑排序排出组内的顺序。为了实现方便,用 map 给虚拟分组标记编号。如下图,将 3,4,6 三个任务打包到 0 号分组里面,将 2,5 两个任务打包到 1 号分组里面,其他任务单独各自为一组。组间的依赖是 6 号任务依赖 1 号任务。由于 6 号任务封装在 0 号分组里,所以 3 号分组依赖 0 号分组。先组间排序,确定分组顺序,再组内拓扑排序,排出最终顺序。
5858

59-
![https://img.halfrost.com/Leetcode/leetcode_1203_1.png](https://img.halfrost.com/Leetcode/leetcode_1203_1.png)
59+
![](https://img.halfrost.com/Leetcode/leetcode_1203_1.png)
6060

6161
- 上面的解法可以 AC,但是时间太慢了。因为做了一些不必要的操作。有没有可能只用一次拓扑排序呢?将必须要在一起的结点统一依赖一个虚拟结点,例如下图中的虚拟结点 8 和 9 。3,4,6 都依赖 8 号任务,2 和 5 都依赖 9 号任务。1 号任务本来依赖 6 号任务,由于 6 由依赖 8 ,所以添加 1 依赖 8 的边。通过增加虚拟结点,增加了需要打包在一起结点的入度。构建出以上关系以后,按照入度为 0 的原则,依次进行 DFS。8 号和 9 号两个虚拟结点的入度都为 0 ,对它们进行 DFS,必定会使得与它关联的节点都被安排在一起,这样就满足了题意:同一小组的项目,排序后在列表中彼此相邻。一遍扫完,满足题意的顺序就排出来了。这个解法 beat 100%!
6262

63-
![https://img.halfrost.com/Leetcode/leetcode_1203_2.png](https://img.halfrost.com/Leetcode/leetcode_1203_2.png)
63+
![](https://img.halfrost.com/Leetcode/leetcode_1203_2.png)
6464

6565
## 代码
6666

website/content/ChapterFour/0125.Valid-Palindrome.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,11 @@ For the purpose of this problem, we define empty string as valid palindrome.
3434
package leetcode
3535

3636
import (
37-
"strings"
37+
"strings"
3838
)
3939

4040
func isPalindrome(s string) bool {
41-
42-
s = strings.ToLower(s)
43-
41+
s = strings.ToLower(s)
4442
i, j := 0, len(s)-1
4543
for i < j {
4644
for i < j && !isChar(s[i]) {
@@ -55,7 +53,6 @@ func isPalindrome(s string) bool {
5553
i++
5654
j--
5755
}
58-
5956
return true
6057
}
6158

website/content/ChapterFour/0174.Dungeon-Game.md

+14-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,20 @@ For example, given the dungeon below, the initial health of the knight must be a
4141
## 解题思路
4242

4343
- 在二维地图上给出每个格子扣血数,负数代表扣血,正数代表补血。左上角第一个格子是起点,右下角最后一个格子是终点。问骑士初始最少多少血才能走完迷宫,顺利营救位于终点的公主。需要注意的是,起点和终点都会对血量进行影响。每到一个格子,骑士的血都不能少于 1,一旦少于 1 点血,骑士就会死去。
44-
- 这一题首先想到的解题思路是动态规划。从终点逆推回起点。`dp[i][j]` 代表骑士进入坐标为 `(i,j)` 的格子之前最少的血量值。 那么 `dp[m-1][n-1]` 应该同时满足两个条件,`dp[m-1][n-1] + dungeon[m-1][n-1] ≥ 1` 并且 `dp[m-1][n-1] ≥ 1`,由于这两个不等式的方向是相同的,取交集以后,起决定作用的是数轴最右边的数,即 `max(1-dungeon[m-1][n-1] , 1)`。算出 `dp[m-1][n-1]` 以后,接着可以推出 `dp[m-1][i]` 这一行和 `dp[i][n-1]` 这一列的值。因为骑士只能往右走和往下走。往回推,即只能往上走和往左走。到这里,DP 的初始条件都准备好了。那么状态转移方程是什么呢?分析一般的情况,`dp[i][j]` 这个值应该是和 `dp[i+1][j]` 和 `dp[i][j+1]` 这两者有关系。即 `dp[i][j]` 经过自己本格子的扣血以后,要能至少满足下一行和右一列格子血量的最少要求。并且自己的血量也应该 `≥1`。即需要满足下面这两组不等式。
45-
\begin{matrix} \left\{ \begin{array}{lr} dp[i][j] + dungeon[i][j] \geqslant dp[i+1][j] \\ dp[i][j] \geqslant 1 \end{array} \right. \end{matrix}
46-
\begin{matrix} \left\{ \begin{array}{lr} dp[i][j] + dungeon[i][j] \geqslant dp[i][j+1] \\ dp[i][j] \geqslant 1 \end{array} \right. \end{matrix}
47-
![](https://img.halfrost.com/Leetcode/leetcode_174_1.png)
48-
![](https://img.halfrost.com/Leetcode/leetcode_174_2.png)
44+
- 这一题首先想到的解题思路是动态规划。从终点逆推回起点。`dp[i][j]` 代表骑士进入坐标为 `(i,j)` 的格子之前最少的血量值。 那么 `dp[m-1][n-1]` 应该同时满足两个条件,`dp[m-1][n-1] + dungeon[m-1][n-1] ≥ 1` 并且 `dp[m-1][n-1] ≥ 1`,由于这两个不等式的方向是相同的,取交集以后,起决定作用的是数轴最右边的数,即 `max(1-dungeon[m-1][n-1] , 1)`。算出 `dp[m-1][n-1]` 以后,接着可以推出 `dp[m-1][i]` 这一行和 `dp[i][n-1]` 这一列的值。因为骑士只能往右走和往下走。往回推,即只能往上走和往左走。到这里,DP 的初始条件都准备好了。那么状态转移方程是什么呢?分析一般的情况,`dp[i][j]` 这个值应该是和 `dp[i+1][j]` 和 `dp[i][j+1]` 这两者有关系。即 `dp[i][j]` 经过自己本格子的扣血以后,要能至少满足下一行和右一列格子血量的最少要求。并且自己的血量也应该 `≥1`。即需要满足下面这两组不等式。
45+
46+
{{< katex display >}}
47+
\begin{matrix} \left\{
48+
\begin{array}{lr}
49+
dp[i][j] + dungeon[i][j] \geqslant dp[i+1][j] \\
50+
dp[i][j] \geqslant 1
51+
\end{array} \right.
52+
\end{matrix}
53+
{{< /katex >}}
54+
55+
{{< katex display >}}
56+
\begin{matrix} \left\{ \begin{array}{lr} dp[i][j] + dungeon[i][j] \geqslant dp[i][j+1] \\ dp[i][j] \geqslant 1 \end{array} \right. \end{matrix}
57+
{{< /katex >}}
4958
上面不等式中第一组不等式是满足下一行格子的最低血量要求,第二组不等式是满足右一列格子的最低血量要求。第一个式子化简即 `dp[i][j] = max(1, dp[i+1][j]-dungeon[i][j])`,第二个式子化简即 `dp[i][j] = max(1, dp[i][j+1]-dungeon[i][j])`。求得了这两种走法的最低血量值,从这两个值里面取最小,即是当前格子所需的最低血量,所以状态转移方程为 `dp[i][j] = min(max(1, dp[i][j+1]-dungeon[i][j]), max(1, dp[i+1][j]-dungeon[i][j]))`。DP 完成以后,`dp[0][0]` 中记录的就是骑士初始最低血量值。时间复杂度 O(m\*n),空间复杂度 O(m\*n)。
5059

5160
- 这一题还可以用二分搜索来求解。骑士的血量取值范围一定是在 `[1,+∞)` 这个区间内。那么二分这个区间,每次二分的中间值,再用 dp 在地图中去判断是否能到达终点,如果能,就缩小搜索空间至 `[1,mid]`,否则搜索空间为 `[mid + 1,+∞)` 。时间复杂度 O(m\*n\* log math.MaxInt64),空间复杂度 O(m\*n)。

website/content/ChapterFour/0483.Smallest-Good-Base.md

+19-18
Original file line numberDiff line numberDiff line change
@@ -51,46 +51,47 @@ Now given a string representing n, you should return the smallest good base of n
5151
- 给出一个数 n,要求找一个进制 k,使得数字 n 在 k 进制下每一位都是 1 。求最小的进制 k。
5252
- 这一题等价于求最小的正整数 k,满足存在一个正整数 m 使得
5353

54-
<p align='center'>
55-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_1.png'>
56-
</p>
54+
{{< katex display >}}
55+
\sum_{i=0}^{m} k^{i} = \frac{1-k^{m+1}}{1-k} = n
56+
{{< /katex >}}
5757

5858

5959
- 这一题需要确定 k 和 m 两个数的值。m 和 k 是有关系的,确定了一个值,另外一个值也确定了。由
6060

61-
<p align='center'>
62-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_2.png'>
63-
</p>
61+
{{< katex display >}}
62+
\frac{1-k^{m+1}}{1-k} = n \\
63+
{{< /katex >}}
6464

6565

6666
可得:
6767

68-
<p align='center'>
69-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_3.png'>
70-
</p>
68+
{{< katex display >}}
69+
m = log_{k}(kn-n+1) - 1 < log_{k}(kn) = 1 + log_{k}n
70+
{{< /katex >}}
7171

7272

7373
根据题意,可以知道 k ≥2,m ≥1 ,所以有:
7474

75-
<p align='center'>
76-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_4.png'>
77-
</p>
75+
{{< katex display >}}
76+
1 \leqslant m \leqslant log_{2}n
77+
{{< /katex >}}
7878

7979

8080
所以 m 的取值范围确定了。那么外层循环从 1 到 log n 遍历。找到一个最小的 k ,能满足:
8181

8282
可以用二分搜索来逼近找到最小的 k。先找到 k 的取值范围。由
8383

84-
<p align='center'>
85-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_5.png'>
86-
</p>
84+
{{< katex display >}}
85+
\frac{1-k^{m+1}}{1-k} = n \\
86+
{{< /katex >}}
8787

8888

8989
可得,
9090

91-
<p align='center'>
92-
<img src='https://img.halfrost.com/Leetcode/leetcode_483_6.png'>
93-
</p>
91+
{{< katex display >}}
92+
k^{m+1} = nk-n+1 < nk\\ \Rightarrow k < \sqrt[m]{n}
93+
{{< /katex >}}
94+
9495

9596
所以 k 的取值范围是 [2, n*(1/m) ]。再利用二分搜索逼近找到最小的 k 即为答案。
9697

website/content/ChapterFour/0793.Preimage-Size-of-Factorial-Zeroes-Function.md

+16-21
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,22 @@ f(x) 是 x! 末尾是0的数量。(回想一下 x! = 1 * 2 * 3 * ... * x
4141
- 给出一个数 K,要求有多少个 n 能使得 n!末尾 0 的个数等于 K。
4242
- 这一题是基于第 172 题的逆过程加强版。第 172 题是给出 `n`,求得末尾 0 的个数。由第 172 题可以知道,`n!`末尾 0 的个数取决于因子 5 的个数。末尾可能有 `K` 个 0,那么 `n` 最多可以等于 `5 * K`,在 `[0, 5* K]` 区间内二分搜索,判断 `mid` 末尾 0 的个数,如果能找到 `K`,那么就范围 5,如果找不到这个 `K`,返回 0 。为什么答案取值只有 0 和 5 呢?因为当 `n` 增加 5 以后,因子 5 的个数又加一了,末尾又可以多 1 个或者多个 0(如果加 5 以后,有多个 5 的因子,例如 25,125,就有可能末尾增加多个 0)。所以有效的 `K` 值对应的 `n` 的范围区间就是 5 。反过来,无效的 `K` 值对应的 `n` 是 0。`K` 在 `5^n` 的分界线处会发生跳变,所有有些值取不到。例如,`n` 在 `[0,5)` 内取值,`K = 0`;`n` 在 `[5,10)` 内取值,`K = 1`;`n` 在 `[10,15)` 内取值,`K = 2`;`n` 在 `[15,20)` 内取值,`K = 3`;`n` 在 `[20,25)` 内取值,`K = 4`;`n` 在 `[25,30)` 内取值,`K = 6`,因为 25 提供了 2 个 5,也就提供了 2 个 0,所以 `K` 永远无法取值等于 5,即当 `K = 5` 时,找不到任何的 `n` 与之对应。
4343
- 这一题也可以用数学的方法解题。见解法二。这个解法的灵感来自于:n!末尾 0 的个数等于 [1,n] 所有数的因子 5 的个数总和。其次此题的结果一定只有 0 和 5 (分析见上一种解法)。有了这两个结论以后,就可以用数学的方法推导了。首先 n 可以表示为 5 进制的形式
44-
<p align='center'>
45-
<img src='https://img.halfrost.com/Leetcode/leetcode_793_1.png'>
46-
</p>
47-
上面式子中,所有有因子 5 的个数为:
48-
<p align='center'>
49-
<img src='https://img.halfrost.com/Leetcode/leetcode_793_2.png'>
50-
</p>
51-
52-
这个总数就即是 K。针对不同的 n,an 的通项公式不同,所以表示的 K 的系数也不同。cn 的通项公式呢?
53-
<p align='center'>
54-
<img src='https://img.halfrost.com/Leetcode/leetcode_793_2.png'>
55-
</p>
56-
<p align='center'>
57-
<img src='https://img.halfrost.com/Leetcode/leetcode_793_3.png'>
58-
</p>
59-
60-
由上面这个递推还能推出通项公式(不过这题不适用通项公式,是用递推公式更方便):
61-
<p align='center'>
62-
<img src='https://img.halfrost.com/Leetcode/leetcode_793_4.png'>
63-
</p>
64-
判断 K 是否能表示成两个数列的表示形式,等价于判断 K 是否能转化为以 Cn 为基的变进制数。到此,转化成类似第 483 题了。代码实现不难,见解法二。
44+
{{< katex display >}}
45+
n = 5^{0} * a_{0} + 5^{1} * a_{1} + 5^{2} * a_{2} + ... + 5^{n} * a_{n}, (a_{n} < 5)
46+
{{< /katex >}}
47+
上面式子中,所有有因子 5 的个数为:
48+
{{< katex display >}}
49+
K = \sum_{n=0}^{n} a_{n} * c_{n}
50+
{{< /katex >}}
51+
这个总数就即是 K。针对不同的 n,an 的通项公式不同,所以表示的 K 的系数也不同。cn 的通项公式呢?
52+
{{< katex display >}}
53+
c_{n} = 5 * c_{n-1} + 1,c_{0} = 0
54+
{{< /katex >}}
55+
由上面这个递推还能推出通项公式(不过这题不适用通项公式,是用递推公式更方便):
56+
{{< katex display >}}
57+
c_{n} = \frac{5^{n} - 1 }{4}
58+
{{< /katex >}}
59+
判断 K 是否能表示成两个数列的表示形式,等价于判断 K 是否能转化为以 Cn 为基的变进制数。到此,转化成类似第 483 题了。代码实现不难,见解法二。
6560

6661

6762
## 代码

website/content/ChapterFour/0887.Super-Egg-Drop.md

+32-42
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,10 @@ What is the minimum number of moves that you need to know with certainty what 
5656

5757
- 给出 `K` 个鸡蛋,`N` 层楼,要求确定安全楼层 `F` 需要最小步数 `t`
5858
- 这一题是微软的经典面试题。拿到题最容易想到的是二分搜索。但是仔细分析以后会发现单纯的二分是不对的。不断的二分确实能找到最终安全的楼层,但是这里没有考虑到 `K` 个鸡蛋。鸡蛋数的限制会导致二分搜索无法找到最终楼层。题目要求要在保证能找到最终安全楼层的情况下,找到最小步数。所以单纯的二分搜索并不能解答这道题。
59-
- 这一题如果按照题意正向考虑,动态规划的状态转移方程是 `searchTime(K, N) = max( searchTime(K-1, X-1), searchTime(K, N-X) )`。其中 `X` 是丢鸡蛋的楼层。随着 `X``[1,N]`,都能计算出一个 `searchTime` 的值,在所有这 `N` 个值之中,取最小值就是本题的答案了。这个解法可以 AC 这道题。不过这个解法不细展开了。时间复杂度 `O(k*N^2)`
60-
<p align='center'>
61-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_8.png'>
62-
</p>
63-
59+
- 这一题如果按照题意正向考虑,动态规划的状态转移方程是 `searchTime(K, N) = max( searchTime(K-1, X-1), searchTime(K, N-X) )`。其中 `X` 是丢鸡蛋的楼层。随着 `X``[1,N]`,都能计算出一个 `searchTime` 的值,在所有这 `N` 个值之中,取最小值就是本题的答案了。这个解法可以 AC 这道题。不过这个解法不细展开了。时间复杂度 `O(k*N^2)`
60+
{{< katex display >}}
61+
dp(K,N) = MIN \begin{bmatrix} \, \, MAX(dp(K-1,X-1),dp(K,N-X))\, \, \end{bmatrix} ,1\leqslant x \leqslant N \\
62+
{{< /katex >}}
6463
- 换个角度来看这个问题,定义 `dp[k][m]` 代表 `K` 个鸡蛋,`M` 次移动能检查的最大楼层。考虑某一步 `t` 应该在哪一层丢鸡蛋呢?一个正确的选择是在 `dp[k-1][t-1] + 1` 层丢鸡蛋,结果分两种情况:
6564
1. 如果鸡蛋碎了,我们首先排除了该层以上的所有楼层(不管这个楼有多高),而对于剩下的 `dp[k-1][t-1]` 层楼,我们一定能用 `k-1` 个鸡蛋在 `t-1` 步内求解。因此这种情况下,我们总共可以求解无限高的楼层。可见,这是一种非常好的情况,但并不总是发生。
6665
2. 如果鸡蛋没碎,我们首先排除了该层以下的 `dp[k-1][t-1]` 层楼,此时我们还有 `k` 个蛋和 `t-1` 步,那么我们去该层以上的楼层继续测得 `dp[k][t-1]` 层楼。因此这种情况下,我们总共可以求解 `dp[k-1][t-1] + 1 + dp[k][t-1]` 层楼。
@@ -70,43 +69,34 @@ What is the minimum number of moves that you need to know with certainty what 
7069
2. 如果在更高的楼层丢鸡蛋,假设是第 `dp[k-1][t-1] + 2` 层丢鸡蛋,如果这次鸡蛋碎了,剩下 `k-1` 个鸡蛋和 `t-1` 步只能保证验证 `dp[k-1][t-1]` 的楼层,这里还剩**** `dp[k-1][t-1]+ 1` 的楼层,不能保证最终一定能找到安全楼层了。
7170
- 用反证法就能得出每一步都应该在第 `dp[k-1][t-1] + 1` 层丢鸡蛋。
7271
- 这道题还可以用二分搜索来解答。回到上面分析的状态转移方程:`dp[k][m] = dp[k-1][m-1] + dp[k][m-1] + 1` 。用数学方法来解析这个递推关系。令 `f(t,k)``t``k` 的函数,题目所要求能测到最大楼层是 `N` 的最小步数,即要求出 `f(t,k) ≥ N` 时候的最小 `t`。由状态转移方程可以知道:`f(t,k) = f(t-1,k) + f(t-1,k-1) + 1`,当 `k = 1` 的时候,对应一个鸡蛋的情况,`f(t,1) = t`,当 `t = 1` 的时候,对应一步的情况,`f(1,k) = 1`。有状态转移方程得:
73-
<p align='center'>
74-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_1.png'>
75-
</p>
76-
77-
-`g(t,k) = f(t,k) - f(t,k-1)`,可以得到:
78-
79-
<p align='center'>
80-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_2.png'>
81-
</p>
82-
83-
- 可以知道 `g(t,k)` 是一个杨辉三角,即二项式系数:
84-
85-
<p align='center'>
86-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_3.png'>
87-
</p>
88-
89-
- 利用裂项相消的方法:
90-
<p align='center'>
91-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_4.png'>
92-
</p>
93-
94-
- 于是可以得到:
95-
<p align='center'>
96-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_5.png'>
97-
</p>
98-
99-
- 其中:
100-
<p align='center'>
101-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_6.png'>
102-
</p>
103-
104-
- 于是针对每一项的二项式常数,都可以由前一项乘以一个分数得到下一项。
105-
<p align='center'>
106-
<img src='https://img.halfrost.com/Leetcode/leetcode_887_7.png'>
107-
</p>
108-
109-
- 利用二分搜索,不断的二分 `t`,直到逼近找到 `f(t,k) ≥ N` 时候最小的 `t`。时间复杂度 `O(K * log N)`,空间复杂度 `O(1)`
72+
{{< katex display >}}
73+
\begin{aligned} f(t,k) &= 1 + f(t-1,k-1) + f(t-1,k) \\ f(t,k-1) &= 1 + f(t-1,k-2) + f(t-1,k-1) \\ \end{aligned}
74+
{{< /katex >}}
75+
`g(t,k) = f(t,k) - f(t,k-1)`,可以得到:
76+
{{< katex display >}}
77+
g(t,k) = g(t-1,k) + g(t-1,k-1)
78+
{{< /katex >}}
79+
可以知道 `g(t,k)` 是一个杨辉三角,即二项式系数:
80+
{{< katex display >}}
81+
g(t,k) = \binom{t}{k+1} = C_{t}^{k+1}
82+
{{< /katex >}}
83+
利用裂项相消的方法:
84+
{{< katex display >}}
85+
\begin{aligned} g(t,x) &= f(t,x) - f(t,x-1) \\ g(t,x-1) &= f(t,x-1) - f(t,x-2) \\ g(t,x-2) &= f(t,x-2) - f(t,x-3) \\ \begin{matrix} .\\ .\\ .\\ \end{matrix}\\ g(t,2) &= f(t,2) - f(t,1) \\ g(t,1) &= f(t,1) - f(t,0) \\ \end{aligned}
86+
{{< /katex >}}
87+
于是可以得到:
88+
{{< katex display >}}
89+
\begin{aligned} f(t,k) &= \sum_{1}^{k}g(t,x) = \sum_{0}^{k} \binom{t}{x} \\ &= C_{t}^{0} + C_{t}^{1} + C_{t}^{2} + ... + C_{t}^{k} \\ \end{aligned}
90+
{{< /katex >}}
91+
其中:
92+
{{< katex display >}}
93+
\begin{aligned} C_{t}^{k} \cdot \frac{n-k}{k+1} &= C_{t}^{k+1} \\ C_{t}^{k} &= C_{t}^{k-1} \cdot \frac{t-k+1}{k} \\ \end{aligned}
94+
{{< /katex >}}
95+
于是针对每一项的二项式常数,都可以由前一项乘以一个分数得到下一项。
96+
{{< katex display >}}
97+
\begin{aligned} C_{t}^{0} &= 1 \\ C_{t}^{1} &= C_{t}^{0} \cdot \frac{t-1+1}{1} \\ C_{t}^{2} &= C_{t}^{1} \cdot \frac{t-2+1}{2} \\ C_{t}^{3} &= C_{t}^{2} \cdot \frac{t-3+1}{3} \\ \begin{matrix} .\\ .\\ .\\ \end{matrix}\\ C_{t}^{k} &= C_{t}^{k-1} \cdot \frac{t-k+1}{k} \\ \end{aligned}
98+
{{< /katex >}}
99+
利用二分搜索,不断的二分 `t`,直到逼近找到 `f(t,k) ≥ N` 时候最小的 `t`。时间复杂度 `O(K * log N)`,空间复杂度 `O(1)`
110100

111101

112102

0 commit comments

Comments
 (0)