Taro Logo

Poor Pigs

Hard
Google logo
Google
1 view
Topics:
Bit ManipulationGreedy Algorithms

There are buckets buckets of liquid, where exactly one of the buckets is poisonous. You have minutesToTest minutes to determine which bucket is poisonous. If a pig drinks from the poisonous bucket, it will die after minutesToDie minutes. The goal is to determine the minimum number of pigs needed to find the poisonous bucket within the allotted time. Pigs can drink from multiple buckets simultaneously, and multiple pigs can drink from the same bucket.

For example:

If buckets = 4, minutesToDie = 15, and minutesToTest = 15, return 2.

If buckets = 4, minutesToDie = 15, and minutesToTest = 30, return 2.

Constraints:

  • 1 <= buckets <= 1000
  • 1 <= minutesToDie <= minutesToTest <= 100

Solution


Naive Approach

A brute-force approach would involve testing each bucket individually. With only minutesToTest and minutesToDie available, we can perform tests = minutesToTest / minutesToDie tests. If buckets is less than or equal to tests, we only need one pig. Otherwise, we need multiple pigs. The problem is that the number of pigs we would need quickly goes up. This approach doesn't scale at all.

Optimal Approach: Base Conversion

The core idea is to use pigs as 'digits' in a base system where the base is the number of times we can test within the given time. Each pig can represent one dimension in this base system. The number of possible states dictates how many buckets the pigs can differentiate.

  1. Determine the Number of Tests: Calculate how many rounds of testing can be done: tests = minutesToTest / minutesToDie. If tests is 1, it means we can only run one test.
  2. Calculate the Required Number of Pigs: The minimum number of pigs is the smallest p such that (tests + 1)^p >= buckets. This translates to finding the base tests + 1 logarithm of buckets and rounding up to the nearest integer.

Edge Cases

  • If there is only one bucket, no pigs are needed.
  • If minutesToDie is equal to minutesToTest, then we only have one chance to test. Each pig can only provide two results: die or survive, which can represent 2 buckets at max.

Example

buckets = 1000, minutesToDie = 15, minutesToTest = 60 tests = 60 / 15 = 4 We need to find the minimum p such that 5^p >= 1000. 5^1 = 5 5^2 = 25 5^3 = 125 5^4 = 625 5^5 = 3125 So, p = 5 pigs are needed.

Code

import math

def poorPigs(buckets: int, minutesToDie: int, minutesToTest: int) -> int:
    if buckets == 1:
        return 0
    
    tests = minutesToTest // minutesToDie
    return math.ceil(math.log(buckets, tests + 1))

Big O Analysis

  • Time Complexity: O(1) - The calculations are constant time operations.
  • Space Complexity: O(1) - Constant space is used.