高级农民
- 积分
- 4019
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-1-22
- 最后登录
- 1970-1-1
|
3296. Minimum Number of Seconds to Make Mountain Height Zero
You are given an integer mountainHeight denoting the height of a mountain.
You are also given an integer array workerTimes representing the work time of workers in seconds.
The workers work simultaneously to reduce the height of the mountain. For worker i:
To decrease the mountain's height by x, it takes workerTimes[i] + workerTimes[i] * 2 + ... + workerTimes[i] * x seconds. For example:
To reduce the height of the mountain by 1, it takes workerTimes[i] seconds.
To reduce the height of the mountain by 2, it takes workerTimes[i] + workerTimes[i] * 2 seconds, and so on.
Return an integer representing the minimum number of seconds required for the workers to make the height of the mountain 0.
Example 1:
Input: mountainHeight = 4, workerTimes = [2,1,1]
Output: 3
Explanation:
One way the height of the mountain can be reduced to 0 is:
Worker 0 reduces the height by 1, taking workerTimes[0] = 2 seconds.
Worker 1 reduces the height by 2, taking workerTimes[1] + workerTimes[1] * 2 = 3 seconds.
Worker 2 reduces the height by 1, taking workerTimes[2] = 1 second.
Since they work simultaneously, the minimum time needed is max(2, 3, 1) = 3 seconds.
Example 2:
Input: mountainHeight = 10, workerTimes = [3,2,2,4]
Output: 12
Explanation:
Worker 0 reduces the height by 2, taking workerTimes[0] + workerTimes[0] * 2 = 9 seconds.
Worker 1 reduces the height by 3, taking workerTimes[1] + workerTimes[1] * 2 + workerTimes[1] * 3 = 12 seconds.
Worker 2 reduces the height by 3, taking workerTimes[2] + workerTimes[2] * 2 + workerTimes[2] * 3 = 12 seconds.
Worker 3 reduces the height by 2, taking workerTimes[3] + workerTimes[3] * 2 = 12 seconds.
The number of seconds needed is max(9, 12, 12, 12) = 12 seconds.
Example 3:
Input: mountainHeight = 5, workerTimes = [1]
Output: 15
Explanation:
There is only one worker in this example, so the answer is workerTimes[0] + workerTimes[0] * 2 + workerTimes[0] * 3 + workerTimes[0] * 4 + workerTimes[0] * 5 = 15.
Constraints:
1 <= mountainHeight <= 105
1 <= workerTimes.length <= 104
1 <= workerTimes[i] <= 106
1. 识别“二分答案”的信号灯这是本题最重要的直觉。当你看到以下特征时,大脑应立刻闪现“二分”:求最值:题目问的是“最小的时间”、“最大的距离”、“最少的开销”。单调性:随着变量(时间)的增加,结果(总高度)一定是非递减的。Check 容易,直接求难:直接计算“$T$ 时间内能降多少高度”很简单(数学公式),但反过来问“降 $H$ 高度最少要多少秒”却很难直接分配任务。2. 数学公式的推导与陷阱在面试中,数学推导一定要在草稿纸上写清楚,不要只在大脑里模拟:等差数列求和:熟练掌握 $\sum_{i=1}^{x} i = \frac{x(x+1)}{2}$。一元二次方程求根:$ax^2 + bx + c = 0$ 的根为 $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$。精度与整数:在 Python 中,int(math.sqrt(...)) 之后要小心,如果数值极大(超过 $10^{15}$),浮点数可能会有微小误差。稳妥方案:如果担心精度,check 函数内部也可以用一个小二分来找每个工人的 $x$。3. 二分查找的“防坑”三板斧为了避免死循环和边界错误,请记住这套标准模板:确定边界:l 取最小值(1),r 取一个绝对能完成的最大值(例如最慢工人做完全部)。循环条件:统一使用 while l <= r。更新逻辑:满足条件:记录答案 ans = mid,尝试更小 r = mid - 1。不满足条件:尝试更大 l = mid + 1。教训:永远不要写 l = mid 或 r = mid,这在 l=5, r=6 时极易导致死循环。4. 性能优化意识(面试加分项)早停(Early Exit):在 check 函数中,如果当前的 total_height 已经大于等于目标高度,直接 return True。没必要算出所有工人的贡献,这能显著降低运行时间。选择合适的边界:右边界 r 设得越准,二分次数越少。比如取 min(workerTimes) * H * (H+1) // 2 比随便给个 $10^{18}$ 要专业得多。5. 扩展思考:如果二分失效怎么办?如果这道题的高度 $H$ 特别小(比如 $H=100$),但工人特别多,那么用**优先队列(最小堆)**模拟每一秒的过程可能更直观。教训:不要只会一种方法。二分适合“大高度、大时间”;堆适合“小高度、动态决策”。 - class Solution:
- def minNumberOfSeconds(self, mountainHeight: int, workerTimes: List[int]) -> int:
- # hard to aggrange each worker working time length
- # easy to get total work done for all works at time T
- def check(T):
- total = 0
- # for worker w
- # Assume it can reduce height x in time T
- # w * 1 + w * 2 + ... + w * x <= T
- # == > x(x+1) * w <= T
- # == > x^2 + x - 2T/w <= 0
- # == > x >= (sqrt(8 * T / w + 1) -1 ) /2, negative x is not right
- for w in workerTimes:
- total += int((math.sqrt( 8 * T // w + 1 ) -1 ) / 2)
- if total >= mountainHeight:
- return True
- return total >= mountainHeight
- # binary serach
- l = 1
- r = (mountainHeight + 1) * mountainHeight * min(workerTimes) // 2
-
- ans = r
- while l <= r:
- mid = (l + r) // 2
- if check(mid):
- r = mid - 1
- ans = mid
- else:
- l = mid + 1
- return ans
复制代码 |
|