mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-05 08:27:30 +08:00
添加 problem 991
This commit is contained in:
@ -59,7 +59,8 @@ What is the minimum number of moves that you need to know with certainty what
|
||||
- 这一题如果按照题意正向考虑,动态规划的状态转移方程是 `searchTime(K, N) = max( searchTime(K-1, X-1), searchTime(K, N-X) )`。其中 `X` 是丢鸡蛋的楼层。随着 `X` 从 `[1,N]`,都能计算出一个 `searchTime` 的值,在所有这 `N` 个值之中,取最小值就是本题的答案了。这个解法可以 AC 这道题。不过这个解法不细展开了。时间复杂度 `O(k*N^2)`。
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_8.png'>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
- 换个角度来看这个问题,定义 `dp[k][m]` 代表 `K` 个鸡蛋,`M` 次移动能检查的最大楼层。考虑某一步 `t` 应该在哪一层丢鸡蛋呢?一个正确的选择是在 `dp[k-1][t-1] + 1` 层丢鸡蛋,结果分两种情况:
|
||||
1. 如果鸡蛋碎了,我们首先排除了该层以上的所有楼层(不管这个楼有多高),而对于剩下的 `dp[k-1][t-1]` 层楼,我们一定能用 `k-1` 个鸡蛋在 `t-1` 步内求解。因此这种情况下,我们总共可以求解无限高的楼层。可见,这是一种非常好的情况,但并不总是发生。
|
||||
2. 如果鸡蛋没碎,我们首先排除了该层以下的 `dp[k-1][t-1]` 层楼,此时我们还有 `k` 个蛋和 `t-1` 步,那么我们去该层以上的楼层继续测得 `dp[k][t-1]` 层楼。因此这种情况下,我们总共可以求解 `dp[k-1][t-1] + 1 + dp[k][t-1]` 层楼。
|
||||
@ -68,33 +69,42 @@ What is the minimum number of moves that you need to know with certainty what
|
||||
1. 如果在更低的楼层丢鸡蛋也能保证找到安全楼层。那么得到的结果一定不是最小步数。因为这次丢鸡蛋没有充分的展现鸡蛋和移动次数的潜力,最终求解一定会有鸡蛋和步数剩余,即不是能探测的最大楼层了。
|
||||
2. 如果在更高的楼层丢鸡蛋,假设是第 `dp[k-1][t-1] + 2` 层丢鸡蛋,如果这次鸡蛋碎了,剩下 `k-1` 个鸡蛋和 `t-1` 步只能保证验证 `dp[k-1][t-1]` 的楼层,这里还剩**第** `dp[k-1][t-1]+ 1` 的楼层,不能保证最终一定能找到安全楼层了。
|
||||
- 用反证法就能得出每一步都应该在第 `dp[k-1][t-1] + 1` 层丢鸡蛋。
|
||||
- 这道题还可以用二分搜索来解答。回到上面分析的状态转移方程:`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`。有状态转移方程得:
|
||||
- 这道题还可以用二分搜索来解答。回到上面分析的状态转移方程:`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`。有状态转移方程得:
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_1.png'>
|
||||
</p>
|
||||
令 `g(t,k) = f(t,k) - f(t,k-1)`,可以得到:
|
||||
</p>
|
||||
|
||||
- 令 `g(t,k) = f(t,k) - f(t,k-1)`,可以得到:
|
||||
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_2.png'>
|
||||
</p>
|
||||
可以知道 `g(t,k)` 是一个杨辉三角,即二项式系数:
|
||||
</p>
|
||||
|
||||
- 可以知道 `g(t,k)` 是一个杨辉三角,即二项式系数:
|
||||
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_3.png'>
|
||||
</p>
|
||||
利用裂项相消的方法:
|
||||
|
||||
- 利用裂项相消的方法:
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_4.png'>
|
||||
</p>
|
||||
于是可以得到:
|
||||
|
||||
- 于是可以得到:
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_5.png'>
|
||||
</p>
|
||||
其中:
|
||||
|
||||
- 其中:
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_6.png'>
|
||||
</p>
|
||||
于是针对每一项的二项式常数,都可以由前一项乘以一个分数得到下一项。
|
||||
|
||||
- 于是针对每一项的二项式常数,都可以由前一项乘以一个分数得到下一项。
|
||||
<p align='center'>
|
||||
<img src='https://img.halfrost.com/Leetcode/leetcode_887_7.png'>
|
||||
</p>
|
||||
利用二分搜索,不断的二分 `t`,直到逼近找到 `f(t,k) ≥ N` 时候最小的 `t`。时间复杂度 `O(K * log N)`,空间复杂度 `O(1)`。
|
||||
|
||||
- 利用二分搜索,不断的二分 `t`,直到逼近找到 `f(t,k) ≥ N` 时候最小的 `t`。时间复杂度 `O(K * log N)`,空间复杂度 `O(1)`。
|
||||
|
||||
|
38
Algorithms/0911. Online Election/911. Online Election.go
Normal file
38
Algorithms/0911. Online Election/911. Online Election.go
Normal file
@ -0,0 +1,38 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// TopVotedCandidate define
|
||||
type TopVotedCandidate struct {
|
||||
persons []int
|
||||
times []int
|
||||
}
|
||||
|
||||
// Constructor911 define
|
||||
func Constructor911(persons []int, times []int) TopVotedCandidate {
|
||||
leaders, votes := make([]int, len(persons)), make([]int, len(persons))
|
||||
leader := persons[0]
|
||||
for i := 0; i < len(persons); i++ {
|
||||
p := persons[i]
|
||||
votes[p]++
|
||||
if votes[p] >= votes[leader] {
|
||||
leader = p
|
||||
}
|
||||
leaders[i] = leader
|
||||
}
|
||||
return TopVotedCandidate{persons: leaders, times: times}
|
||||
}
|
||||
|
||||
// Q define
|
||||
func (tvc *TopVotedCandidate) Q(t int) int {
|
||||
i := sort.Search(len(tvc.times), func(p int) bool { return tvc.times[p] > t })
|
||||
return tvc.persons[i-1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Your TopVotedCandidate object will be instantiated and called as such:
|
||||
* obj := Constructor(persons, times);
|
||||
* param_1 := obj.Q(t);
|
||||
*/
|
@ -0,0 +1,28 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Problem911(t *testing.T) {
|
||||
obj := Constructor911([]int{0, 1, 1, 0, 0, 1, 0}, []int{0, 5, 10, 15, 20, 25, 30})
|
||||
fmt.Printf("obj.Q[3] = %v\n", obj.Q(3)) // 0
|
||||
fmt.Printf("obj.Q[12] = %v\n", obj.Q(12)) // 1
|
||||
fmt.Printf("obj.Q[25] = %v\n", obj.Q(25)) // 1
|
||||
fmt.Printf("obj.Q[15] = %v\n", obj.Q(15)) // 0
|
||||
fmt.Printf("obj.Q[24] = %v\n", obj.Q(24)) // 0
|
||||
fmt.Printf("obj.Q[8] = %v\n", obj.Q(8)) // 1
|
||||
|
||||
obj = Constructor911([]int{0, 0, 0, 0, 1}, []int{0, 6, 39, 52, 75})
|
||||
fmt.Printf("obj.Q[45] = %v\n", obj.Q(45)) // 0
|
||||
fmt.Printf("obj.Q[49] = %v\n", obj.Q(49)) // 0
|
||||
fmt.Printf("obj.Q[59] = %v\n", obj.Q(59)) // 0
|
||||
fmt.Printf("obj.Q[68] = %v\n", obj.Q(68)) // 0
|
||||
fmt.Printf("obj.Q[42] = %v\n", obj.Q(42)) // 0
|
||||
fmt.Printf("obj.Q[37] = %v\n", obj.Q(37)) // 0
|
||||
fmt.Printf("obj.Q[99] = %v\n", obj.Q(99)) // 0
|
||||
fmt.Printf("obj.Q[26] = %v\n", obj.Q(26)) // 0
|
||||
fmt.Printf("obj.Q[78] = %v\n", obj.Q(78)) // 0
|
||||
fmt.Printf("obj.Q[43] = %v\n", obj.Q(43)) // 0
|
||||
}
|
53
Algorithms/0911. Online Election/README.md
Executable file
53
Algorithms/0911. Online Election/README.md
Executable file
@ -0,0 +1,53 @@
|
||||
# [911. Online Election](https://leetcode.com/problems/online-election/)
|
||||
|
||||
|
||||
## 题目:
|
||||
|
||||
In an election, the `i`-th vote was cast for `persons[i]` at time `times[i]`.
|
||||
|
||||
Now, we would like to implement the following query function: `TopVotedCandidate.q(int t)` will return the number of the person that was leading the election at time `t`.
|
||||
|
||||
Votes cast at time `t` will count towards our query. In the case of a tie, the most recent vote (among tied candidates) wins.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
Input: ["TopVotedCandidate","q","q","q","q","q","q"], [[[0,1,1,0,0,1,0],[0,5,10,15,20,25,30]],[3],[12],[25],[15],[24],[8]]
|
||||
Output: [null,0,1,1,0,0,1]
|
||||
Explanation:
|
||||
At time 3, the votes are [0], and 0 is leading.
|
||||
At time 12, the votes are [0,1,1], and 1 is leading.
|
||||
At time 25, the votes are [0,1,1,0,0,1], and 1 is leading (as ties go to the most recent vote.)
|
||||
This continues for 3 more queries at time 15, 24, and 8.
|
||||
|
||||
**Note:**
|
||||
|
||||
1. `1 <= persons.length = times.length <= 5000`
|
||||
2. `0 <= persons[i] <= persons.length`
|
||||
3. `times` is a strictly increasing array with all elements in `[0, 10^9]`.
|
||||
4. `TopVotedCandidate.q` is called at most `10000` times per test case.
|
||||
5. `TopVotedCandidate.q(int t)` is always called with `t >= times[0]`.
|
||||
|
||||
|
||||
## 题目大意
|
||||
|
||||
在选举中,第 i 张票是在时间为 times[i] 时投给 persons[i] 的。
|
||||
|
||||
现在,我们想要实现下面的查询函数: TopVotedCandidate.q(int t) 将返回在 t 时刻主导选举的候选人的编号。
|
||||
|
||||
在 t 时刻投出的选票也将被计入我们的查询之中。在平局的情况下,最近获得投票的候选人将会获胜。
|
||||
|
||||
提示:
|
||||
|
||||
1. 1 <= persons.length = times.length <= 5000
|
||||
2. 0 <= persons[i] <= persons.length
|
||||
3. times 是严格递增的数组,所有元素都在 [0, 10^9] 范围中。
|
||||
4. 每个测试用例最多调用 10000 次 TopVotedCandidate.q。
|
||||
5. TopVotedCandidate.q(int t) 被调用时总是满足 t >= times[0]。
|
||||
|
||||
|
||||
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 给出一个 2 个数组,分别代表第 `i` 人在第 `t` 时刻获得的票数。需要实现一个查询功能的函数,查询在任意 `t` 时刻,输出谁的选票领先。
|
||||
- `persons[]` 数组里面装的是获得选票人的编号,`times[]` 数组里面对应的是每个选票的时刻。`times[]` 数组默认是有序的,从小到大排列。先计算出每个时刻哪个人选票领先,放在一个数组中,实现查询函数的时候,只需要先对 `times[]` 数组二分搜索,找到比查询时间 `t` 小的最大时刻 `i`,再在选票领先的数组里面输出对应时刻领先的人的编号即可。
|
Reference in New Issue
Block a user