This problem asks to find the maximum amount of water that can be equally distributed among multiple buckets, considering water loss during the transfer. A direct approach would involve complex iterative simulations of water pouring. However, a more efficient solution leverages binary search.
Core Idea: The problem exhibits a monotonically increasing property: if a certain water level v
is achievable, then any level below v
is also achievable. This property makes binary search applicable.
Algorithm:
Binary Search: We perform a binary search within the range [0, max(buckets)], where buckets
is the input array representing water levels in each bucket. The search aims to find the largest achievable water level.
Check Function: The core of the algorithm lies in the check(v)
function. This function determines if a given water level v
is feasible. For each bucket:
v
, we calculate the excess water (x - v
) that needs to be poured out.v
, we calculate the water needed to fill it to level v
. This amount is then adjusted to account for the water loss using the formula: (v - x) * 100 / (100 - loss)
.The function returns true
if the total excess water (a
) is greater than or equal to the total water needed (b
), meaning we can equalize the water levels to v
by pouring water between the buckets. Otherwise, it returns false
.
Binary Search Iteration: The binary search iteratively refines the search space. If check(mid)
is true (where mid
is the midpoint of the current search space), we update the lower bound (l
) to mid
; otherwise, we update the upper bound (r
) to mid
. This continues until the difference between r
and l
is smaller than a tolerance (e.g., 1e-5
to account for floating-point precision).
Return Value: After the binary search, l
will hold the maximum achievable water level, which is returned as the result.
Time and Space Complexity:
check
operation takes O(N) time to iterate through the buckets.Code Implementation (Python):
class Solution:
def equalizeWater(self, buckets: List[int], loss: int) -> float:
def check(v):
a = b = 0
for x in buckets:
if x >= v:
a += x - v
else:
b += (v - x) * 100 / (100 - loss)
return a >= b
l, r = 0, max(buckets)
while r - l > 1e-5:
mid = (l + r) / 2
if check(mid):
l = mid
else:
r = mid
return l
The implementations in other languages (Java, C++, Go, TypeScript) follow a very similar structure, differing only in syntax and specific library functions. The core logic of binary search and the check
function remains consistent across all implementations.