Facebook Pixel

3296. Minimum Number of Seconds to Make Mountain Height Zero

Problem Description

You have a mountain with a given height mountainHeight and multiple workers who can work simultaneously to reduce this height to 0. Each worker has their own working speed defined in the array workerTimes.

For each worker i, the time required to reduce the mountain height follows a specific pattern:

  • To reduce height by 1: takes workerTimes[i] seconds
  • To reduce height by 2: takes workerTimes[i] + workerTimes[i] * 2 seconds
  • To reduce height by 3: takes workerTimes[i] + workerTimes[i] * 2 + workerTimes[i] * 3 seconds
  • In general, to reduce height by x: takes workerTimes[i] * (1 + 2 + ... + x) seconds

The key insight is that this forms an arithmetic series. To reduce the height by x, worker i needs: workerTimes[i] * (1 + 2 + ... + x) = workerTimes[i] * x * (x + 1) / 2 seconds

Since workers operate simultaneously, the total time taken is determined by when all workers collectively reduce the mountain height to 0. Each worker can reduce a different amount of height, and we need to find the optimal distribution that minimizes the total time.

The solution uses binary search on the time t. For a given time t, we calculate how much height each worker can reduce. Using the formula above, if worker i reduces height by h' in time t, then: workerTimes[i] * h' * (h' + 1) / 2 ≤ t

Solving this quadratic inequality gives us the maximum height each worker can reduce in time t. The binary search finds the minimum time where the sum of all heights reduced by workers is at least mountainHeight.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key observation is that if we can reduce the mountain to height 0 in t seconds, then we can definitely do it in any time greater than t. This monotonic property immediately suggests binary search on the answer.

Why binary search on time? Consider the alternative - trying to directly calculate the optimal height distribution among workers. This becomes a complex optimization problem because each worker has different efficiency and the cost function is quadratic. However, if we fix the time t, we can easily calculate the maximum height each worker can reduce independently.

For a fixed time t, each worker works independently and we want to maximize their contribution. Given worker i has t seconds, we need to find the maximum height h' they can reduce where: workerTimes[i] * (1 + 2 + ... + h') ≤ t

Using the arithmetic series sum formula: workerTimes[i] * h' * (h' + 1) / 2 ≤ t

This is a quadratic inequality in h'. Rearranging: h'² + h' - 2t/workerTimes[i] ≤ 0

Using the quadratic formula and taking the positive root: h' ≤ (-1 + √(1 + 8t/workerTimes[i])) / 2

Which simplifies to: h' ≤ ⌊√(2t/workerTimes[i] + 1/4) - 1/2⌋

Once we can calculate each worker's maximum contribution for a given time t, we simply sum these contributions. If the total is at least mountainHeight, then time t is sufficient. Otherwise, we need more time.

The binary search bounds are straightforward: the minimum time is close to 0, and the maximum can be estimated by considering the worst case where one slow worker does all the work. Since workerTimes[i] ≤ 10^6 and mountainHeight ≤ 10^5, the upper bound of 10^16 is safe.

Learn more about Greedy, Math, Binary Search and Heap (Priority Queue) patterns.

Solution Implementation

1from typing import List
2from math import sqrt
3
4class Solution:
5    def minNumberOfSeconds(self, mountainHeight: int, workerTimes: List[int]) -> int:
6        """
7        Find the minimum number of seconds needed to reduce the mountain to the target height.
8
9        Each worker reduces height following the pattern: 1 + 2 + 3 + ... + n units,
10        where the time taken is workerTime * (1 + 2 + ... + n) = workerTime * n * (n + 1) / 2
11
12        Args:
13            mountainHeight: The target height to reduce the mountain to
14            workerTimes: List of time coefficients for each worker
15
16        Returns:
17            Minimum seconds needed to complete the task
18        """
19
20        def can_complete_in_time(time_limit: int) -> bool:
21            """
22            Check if workers can reduce the mountain to target height within given time.
23            This is the feasible function for binary search.
24
25            Args:
26                time_limit: Maximum time allowed
27
28            Returns:
29                True if mountain can be reduced to target height within time limit
30            """
31            total_height_reduced = 0
32
33            for worker_time in workerTimes:
34                # Calculate maximum rounds this worker can complete within time_limit
35                # Using the quadratic formula solution for n
36                max_rounds = int(sqrt(2 * time_limit / worker_time + 0.25) - 0.5)
37                total_height_reduced += max_rounds
38
39            return total_height_reduced >= mountainHeight
40
41        # Binary search using standard template to find minimum valid time
42        left, right = 1, 10**16
43        first_true_index = -1
44
45        while left <= right:
46            mid = (left + right) // 2
47            if can_complete_in_time(mid):
48                first_true_index = mid
49                right = mid - 1  # Found valid time, try smaller
50            else:
51                left = mid + 1   # Need more time
52
53        return first_true_index
54
1class Solution {
2    private int mountainHeight;
3    private int[] workerTimes;
4
5    /**
6     * Finds the minimum number of seconds needed for workers to reduce the mountain to ground level.
7     * Uses binary search to find the optimal time.
8     *
9     * @param mountainHeight The initial height of the mountain
10     * @param workerTimes Array where workerTimes[i] represents the time for worker i to reduce height by 1
11     * @return The minimum number of seconds needed
12     */
13    public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {
14        this.mountainHeight = mountainHeight;
15        this.workerTimes = workerTimes;
16
17        // Binary search using standard template
18        long left = 1;
19        long right = (long) 1e16;
20        long firstTrueIndex = -1;
21
22        while (left <= right) {
23            long mid = left + (right - left) / 2;
24
25            if (canCompleteInTime(mid)) {
26                // Feasible: can complete in 'mid' seconds
27                firstTrueIndex = mid;
28                right = mid - 1;  // Try to find smaller time
29            } else {
30                // Not feasible: need more time
31                left = mid + 1;
32            }
33        }
34
35        return firstTrueIndex;
36    }
37
38    /**
39     * Checks if workers can reduce the mountain to ground level within given time.
40     * Each worker reduces height following arithmetic progression: 1st unit takes workerTime[i],
41     * 2nd unit takes 2*workerTime[i], nth unit takes n*workerTime[i].
42     * Total time for n units: workerTime[i] * (1 + 2 + ... + n) = workerTime[i] * n * (n + 1) / 2
43     *
44     * @param timeLimit The time limit to check
45     * @return true if the mountain can be reduced within timeLimit, false otherwise
46     */
47    private boolean canCompleteInTime(long timeLimit) {
48        long totalHeightReduced = 0;
49
50        for (int workerTime : workerTimes) {
51            // For each worker, calculate maximum height they can reduce in timeLimit
52            // Using formula: workerTime * n * (n + 1) / 2 <= timeLimit
53            // Solving for n: n = (-1 + sqrt(1 + 8 * timeLimit / workerTime)) / 2
54            // Simplified: n = sqrt(2 * timeLimit / workerTime + 0.25) - 0.5
55            long maxHeightByWorker = (long) (Math.sqrt(timeLimit * 2.0 / workerTime + 0.25) - 0.5);
56            totalHeightReduced += maxHeightByWorker;
57        }
58
59        // Check if total height reduced by all workers meets the requirement
60        return totalHeightReduced >= mountainHeight;
61    }
62}
63
1class Solution {
2public:
3    long long minNumberOfSeconds(int mountainHeight, vector<int>& workerTimes) {
4        using ll = long long;
5
6        // Binary search bounds: minimum 1 second, maximum 10^16 seconds
7        ll left = 1;
8        ll right = 1e16;
9
10        // Lambda function to check if given time is sufficient to reduce mountain to 0
11        auto canCompleteInTime = [&](ll timeLimit) -> bool {
12            ll totalHeightReduced = 0;
13
14            // For each worker, calculate how much height they can reduce in given time
15            for (int& workerTime : workerTimes) {
16                // Worker reduces height by 1, 2, 3, ... units
17                // Time taken: workerTime * (1 + 2 + 3 + ... + n) = workerTime * n * (n + 1) / 2
18                // Given timeLimit, solve for n: workerTime * n * (n + 1) / 2 <= timeLimit
19                // This gives us a quadratic equation: n^2 + n - 2*timeLimit/workerTime <= 0
20                // Using quadratic formula: n = (-1 + sqrt(1 + 8*timeLimit/workerTime)) / 2
21                // Simplified calculation below
22                totalHeightReduced += static_cast<ll>(sqrt(timeLimit * 2.0 / workerTime + 0.25) - 0.5);
23            }
24
25            // Check if total height reduced meets or exceeds the mountain height
26            return totalHeightReduced >= mountainHeight;
27        };
28
29        // Binary search using standard template
30        ll firstTrueIndex = -1;
31
32        while (left <= right) {
33            ll mid = left + (right - left) / 2;
34
35            if (canCompleteInTime(mid)) {
36                // Feasible: can complete in 'mid' seconds
37                firstTrueIndex = mid;
38                right = mid - 1;  // Try to find smaller time
39            } else {
40                // Not feasible: need more time
41                left = mid + 1;
42            }
43        }
44
45        return firstTrueIndex;
46    }
47};
48
1/**
2 * Calculates the minimum number of seconds needed for workers to reduce a mountain to height 0.
3 * Each worker reduces the mountain height by 1, 2, 3, ... units in successive operations,
4 * taking workerTime * (1 + 2 + ... + k) seconds for k operations.
5 *
6 * @param mountainHeight - The initial height of the mountain to be reduced
7 * @param workerTimes - Array where workerTimes[i] is the time multiplier for worker i
8 * @returns The minimum number of seconds needed to reduce the mountain to height 0
9 */
10function minNumberOfSeconds(mountainHeight: number, workerTimes: number[]): number {
11    /**
12     * Checks if the given time is sufficient for workers to reduce the mountain.
13     * Uses the formula: time = workerTime * k * (k + 1) / 2 for k operations
14     * Solving for k: k = floor((-1 + sqrt(1 + 8 * time / workerTime)) / 2)
15     *
16     * @param timeLimit - The time limit to check
17     * @returns true if workers can reduce the mountain within the time limit
18     */
19    const canCompleteInTime = (timeLimit: bigint): boolean => {
20        let totalHeightReduced = BigInt(0);
21
22        for (const workerTime of workerTimes) {
23            // Calculate maximum operations this worker can perform within time limit
24            // Using quadratic formula: k = (-0.5 + sqrt(0.25 + 2 * time / workerTime))
25            const maxOperations = Math.floor(
26                Math.sqrt((Number(timeLimit) * 2.0) / workerTime + 0.25) - 0.5
27            );
28            totalHeightReduced += BigInt(maxOperations);
29        }
30
31        return totalHeightReduced >= BigInt(mountainHeight);
32    };
33
34    // Binary search using standard template
35    let left = BigInt(1);
36    let right = BigInt(1e16);
37    let firstTrueIndex = BigInt(-1);
38
39    while (left <= right) {
40        const mid = (left + right) / BigInt(2);
41
42        if (canCompleteInTime(mid)) {
43            // Feasible: can complete in 'mid' seconds
44            firstTrueIndex = mid;
45            right = mid - BigInt(1);  // Try to find smaller time
46        } else {
47            // Not feasible: need more time
48            left = mid + BigInt(1);
49        }
50    }
51
52    return Number(firstTrueIndex);
53}
54

Solution Approach

The solution implements a binary search to find the minimum time required. Here's how the implementation works:

Binary Search Setup: We use the standard binary search template to find the first time where the condition becomes True. The feasible condition is: "can workers reduce the mountain in time t?" This creates a pattern like [false, false, ..., true, true, ...] and we find the first true.

left, right = 1, 10**16
first_true_index = -1

while left <= right:
    mid = (left + right) // 2
    if can_complete_in_time(mid):
        first_true_index = mid
        right = mid - 1  # Found valid time, try smaller
    else:
        left = mid + 1   # Need more time

return first_true_index

Check Function: The check(t) function determines if time t is sufficient for workers to reduce the mountain to height 0:

  1. Initialize a counter h = 0 to track the total height reduction

  2. For each worker with time workerTimes[i], calculate the maximum height they can reduce using the formula:

    h += int(sqrt(2 * t / wt + 1 / 4) - 1 / 2)

    This formula comes from solving the quadratic inequality: wt * h' * (h' + 1) / 2 ≤ t

    Which gives us: h' ≤ √(2t/wt + 1/4) - 1/2

  3. Return True if the total height reduction h >= mountainHeight

Why This Formula Works: Given a worker needs wt * h' * (h' + 1) / 2 seconds to reduce height by h', we rearrange to find the maximum h' possible in time t:

  • Start with: wt * h' * (h' + 1) / 2 ≤ t
  • Multiply by 2: wt * h' * (h' + 1) ≤ 2t
  • Expand: wt * h'² + wt * h' ≤ 2t
  • Rearrange: h'² + h' - 2t/wt ≤ 0
  • Complete the square: (h' + 1/2)² ≤ 2t/wt + 1/4
  • Take square root: h' + 1/2 ≤ √(2t/wt + 1/4)
  • Solve for h': h' ≤ √(2t/wt + 1/4) - 1/2

Binary Search Execution: The template efficiently finds the minimum time where can_complete_in_time(t) returns True:

  • Initialize first_true_index = -1 to track the answer
  • Use while left <= right loop structure
  • When feasible (can_complete_in_time(mid) is true), record the answer and search left with right = mid - 1
  • When not feasible, search right with left = mid + 1

The time complexity is O(n * log(10^16)) where n is the number of workers, as we perform the check function O(log(10^16)) times, and each check takes O(n) time to iterate through all workers.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with mountainHeight = 10 and workerTimes = [2, 4].

Step 1: Understanding Worker Capabilities

Worker 0 (time = 2):

  • Reduce by 1: takes 2×1 = 2 seconds
  • Reduce by 2: takes 2×(1+2) = 6 seconds
  • Reduce by 3: takes 2×(1+2+3) = 12 seconds
  • Reduce by 4: takes 2×(1+2+3+4) = 20 seconds

Worker 1 (time = 4):

  • Reduce by 1: takes 4×1 = 4 seconds
  • Reduce by 2: takes 4×(1+2) = 12 seconds
  • Reduce by 3: takes 4×(1+2+3) = 24 seconds

Step 2: Binary Search Process

We binary search on time from 0 to 10^16. Let's check some key time values:

Check t = 10:

  • Worker 0: Using formula h' ≤ √(2×10/2 + 1/4) - 1/2 = √(10.25) - 0.5 ≈ 2.7, so can reduce 2 units
  • Worker 1: Using formula h' ≤ √(2×10/4 + 1/4) - 1/2 = √(5.25) - 0.5 ≈ 1.8, so can reduce 1 unit
  • Total reduction: 2 + 1 = 3 < 10 ❌ (not enough)

Check t = 20:

  • Worker 0: h' ≤ √(2×20/2 + 1/4) - 1/2 = √(20.25) - 0.5 ≈ 4.0, so can reduce 4 units
  • Worker 1: h' ≤ √(2×20/4 + 1/4) - 1/2 = √(10.25) - 0.5 ≈ 2.7, so can reduce 2 units
  • Total reduction: 4 + 2 = 6 < 10 ❌ (not enough)

Check t = 40:

  • Worker 0: h' ≤ √(2×40/2 + 1/4) - 1/2 = √(40.25) - 0.5 ≈ 5.8, so can reduce 5 units
  • Worker 1: h' ≤ √(2×40/4 + 1/4) - 1/2 = √(20.25) - 0.5 ≈ 4.0, so can reduce 4 units
  • Total reduction: 5 + 4 = 9 < 10 ❌ (not enough)

Check t = 42:

  • Worker 0: h' ≤ √(2×42/2 + 1/4) - 1/2 = √(42.25) - 0.5 ≈ 6.0, so can reduce 6 units
  • Worker 1: h' ≤ √(2×42/4 + 1/4) - 1/2 = √(21.25) - 0.5 ≈ 4.1, so can reduce 4 units
  • Total reduction: 6 + 4 = 10 ✓ (sufficient!)

Step 3: Verification

Let's verify t = 42 is correct:

  • Worker 0 reduces 6 units: takes 2×(1+2+3+4+5+6) = 2×21 = 42 seconds
  • Worker 1 reduces 4 units: takes 4×(1+2+3+4) = 4×10 = 40 seconds
  • Both finish within 42 seconds, and 6 + 4 = 10 (mountain fully reduced)

Binary search continues narrowing down between values where the check fails and succeeds, ultimately finding that 42 is the minimum time needed.

Time and Space Complexity

Time Complexity: O(n × log M), where n is the number of workers (length of workerTimes), and M is the upper bound of the binary search range, which is 10^16 in this problem.

The analysis breaks down as follows:

  • The bisect_left function performs a binary search over the range [0, 10^16), which requires O(log M) iterations where M = 10^16
  • For each iteration of the binary search, the check function is called
  • Inside the check function, we iterate through all n workers in workerTimes, performing a constant-time calculation (square root and arithmetic operations) for each worker
  • Therefore, each call to check takes O(n) time
  • The total time complexity is O(n) × O(log M) = O(n × log M)

Space Complexity: O(1)

The space analysis:

  • The check function only uses a constant amount of extra space for the variable h and loop variable
  • The binary search itself only requires constant space for maintaining search boundaries
  • No additional data structures are created that scale with the input size
  • Therefore, the overall space complexity is O(1) (constant space)

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Using Wrong Binary Search Template Variant

Pitfall: Using while left < right with right = mid instead of the standard template:

# WRONG: Non-standard variant
while left < right:
    mid = (left + right) // 2
    if can_complete_in_time(mid):
        right = mid
    else:
        left = mid + 1
return left

Solution: Use the standard template with first_true_index:

# CORRECT: Standard template
first_true_index = -1
while left <= right:
    mid = (left + right) // 2
    if can_complete_in_time(mid):
        first_true_index = mid
        right = mid - 1
    else:
        left = mid + 1
return first_true_index

2. Integer Overflow in Binary Search Upper Bound

Pitfall: Using an inadequate upper bound for binary search can lead to incorrect results for large inputs. The formula workerTime * n * (n + 1) / 2 grows quadratically, and with large mountainHeight and workerTimes, the required time can be substantial.

Solution: Use a sufficiently large upper bound. A safe approach is to calculate the worst-case scenario:

# Calculate a proper upper bound
max_worker_time = max(workerTimes)
# Worst case: single slowest worker does all the work
upper_bound = max_worker_time * mountainHeight * (mountainHeight + 1) // 2

2. Floating Point Precision Errors

Pitfall: The quadratic formula involves square roots and division, which can introduce floating-point precision errors:

# Potential precision issues
max_rounds = int(sqrt(2 * time_limit / worker_time + 0.25) - 0.5)

When time_limit is very large or worker_time is very small, the calculation might lose precision.

Solution: Add a small epsilon for comparison or use integer arithmetic where possible:

def can_complete_in_time(time_limit: int) -> bool:
    total_height_reduced = 0

    for worker_time in workerTimes:
        # Binary search for max_rounds instead of using floating-point formula
        left, right = 0, mountainHeight
        while left < right:
            mid = (left + right + 1) // 2
            if worker_time * mid * (mid + 1) // 2 <= time_limit:
                left = mid
            else:
                right = mid - 1
        total_height_reduced += left

    return total_height_reduced >= mountainHeight

3. Incorrect Quadratic Formula Application

Pitfall: Misapplying the quadratic formula or using the wrong root. The inequality wt * h * (h + 1) / 2 ≤ t leads to a quadratic equation, and choosing the wrong root or making algebraic errors is common.

Solution: Verify the formula derivation and always take the positive root:

# Correct formula with explicit steps
discriminant = 1 + 8 * time_limit / worker_time
if discriminant < 0:
    max_rounds = 0
else:
    # We need the positive root: (-1 + sqrt(discriminant)) / 2
    max_rounds = int((-1 + sqrt(discriminant)) / 2)

4. Division by Zero

Pitfall: If any workerTimes[i] is 0, division by zero occurs in the formula.

Solution: Add validation for edge cases:

def can_complete_in_time(time_limit: int) -> bool:
    total_height_reduced = 0

    for worker_time in workerTimes:
        if worker_time == 0:
            # Worker with 0 time can reduce infinite height instantly
            return True
        max_rounds = int(sqrt(2 * time_limit / worker_time + 0.25) - 0.5)
        total_height_reduced += max_rounds

    return total_height_reduced >= mountainHeight

5. Early Termination Optimization Missing

Pitfall: Continuing to calculate even after we've already reduced enough height wastes computation.

Solution: Add early termination:

def can_complete_in_time(time_limit: int) -> bool:
    total_height_reduced = 0

    for worker_time in workerTimes:
        max_rounds = int(sqrt(2 * time_limit / worker_time + 0.25) - 0.5)
        total_height_reduced += max_rounds

        # Early termination if we've already reduced enough
        if total_height_reduced >= mountainHeight:
            return True

    return total_height_reduced >= mountainHeight
Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

In a binary min heap, the maximum element can be found in:


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More