Taro Logo

Fair Distribution of Cookies

Medium
Amazon logo
Amazon
1 view
Topics:
ArraysBinary SearchGreedy Algorithms

You are given an integer array cookies, where cookies[i] denotes the number of cookies in the ith bag. You are also given an integer k that denotes the number of children to distribute all the bags of cookies to. All the cookies in the same bag must go to the same child and cannot be split up.

The unfairness of a distribution is defined as the maximum total cookies obtained by a single child in the distribution.

Return the minimum unfairness of all distributions.

Example 1:

Input: cookies = [8,15,10,20,8], k = 2
Output: 31

Explanation: One optimal distribution is [8,15,8] and [10,20]

  • The 1st child receives [8,15,8] which has a total of 8 + 15 + 8 = 31 cookies.
  • The 2nd child receives [10,20] which has a total of 10 + 20 = 30 cookies.

The unfairness of the distribution is max(31,30) = 31. It can be shown that there is no distribution with an unfairness less than 31.

Example 2:

Input: cookies = [6,1,3,2,2,4,1,2], k = 3
Output: 7

Explanation: One optimal distribution is [6,1], [3,2,2], and [4,1,2]

  • The 1st child receives [6,1] which has a total of 6 + 1 = 7 cookies.
  • The 2nd child receives [3,2,2] which has a total of 3 + 2 + 2 = 7 cookies.
  • The 3rd child receives [4,1,2] which has a total of 4 + 1 + 2 = 7 cookies.

The unfairness of the distribution is max(7,7,7) = 7. It can be shown that there is no distribution with an unfairness less than 7.

Constraints:

  • 2 <= cookies.length <= 8
  • 1 <= cookies[i] <= 10^5
  • 2 <= k <= cookies.length

Solution


Naive Approach (Brute Force)

A straightforward way to solve this problem is to try all possible distributions of cookies to the k children. Since each bag of cookies can be given to any of the k children, there are k^(number of cookie bags) possible distributions. We can generate all these distributions using recursion, calculate the unfairness for each distribution, and return the minimum unfairness.

Code (Python)

import sys

def distributeCookiesBruteForce(cookies, k):
    n = len(cookies)
    min_unfairness = sys.maxsize

    def calculate_unfairness(distribution):
        child_sums = [0] * k
        for i in range(n):
            child_sums[distribution[i]] += cookies[i]
        return max(child_sums)

    def generate_distributions(index, current_distribution):
        nonlocal min_unfairness
        if index == n:
            unfairness = calculate_unfairness(current_distribution)
            min_unfairness = min(min_unfairness, unfairness)
            return

        for i in range(k):
            current_distribution[index] = i
            generate_distributions(index + 1, current_distribution)

    generate_distributions(0, [0] * n)
    return min_unfairness

# Example usage
cookies = [8, 15, 10, 20, 8]
k = 2
print(distributeCookiesBruteForce(cookies, k))


cookies = [6,1,3,2,2,4,1,2]
k = 3
print(distributeCookiesBruteForce(cookies, k))

Time Complexity

  • O(kn), where n is the number of cookie bags and k is the number of children. This is because we generate all possible distributions.

Space Complexity

  • O(n), primarily due to the depth of the recursion stack.

Optimal Approach (Binary Search + Greedy)

We can significantly improve the time complexity by using a binary search approach. The idea is to binary search for the minimum unfairness. For a given unfairness value x, we check if it's possible to distribute the cookies to k children such that no child receives more than x cookies. This check can be done using a greedy approach.

Algorithm

  1. Define a function is_possible(max_unfairness, cookies, k) that checks if the cookies can be distributed such that no child's total exceeds max_unfairness.
  2. Use binary search to find the minimum possible max_unfairness. The lower bound for the binary search is the maximum value in the cookies array, and the upper bound is the sum of all values in the cookies array.

Code (Python)

import sys

def distributeCookiesOptimal(cookies, k):
    def is_possible(max_unfairness, cookies, k):
        children_needed = 1
        current_sum = 0
        for cookie in cookies:
            if cookie > max_unfairness:
                return False
            if current_sum + cookie <= max_unfairness:
                current_sum += cookie
            else:
                children_needed += 1
                current_sum = cookie
        return children_needed <= k

    left = max(cookies)
    right = sum(cookies)
    ans = right

    while left <= right:
        mid = (left + right) // 2
        if is_possible(mid, cookies, k):
            ans = mid
            right = mid - 1
        else:
            left = mid + 1

    return ans

# Example usage
cookies = [8, 15, 10, 20, 8]
k = 2
print(distributeCookiesOptimal(cookies, k))


cookies = [6,1,3,2,2,4,1,2]
k = 3
print(distributeCookiesOptimal(cookies, k))

Time Complexity

  • O(n log(sum(cookies))), where n is the number of cookie bags. The binary search takes log(sum(cookies)) iterations, and the is_possible function takes O(n) time.

Space Complexity

  • O(1), as we use only a constant amount of extra space.

Edge Cases

  1. Empty cookies array: The problem states that 2 <= cookies.length <= 8, so this case is not possible.
  2. k = 1: The minimum unfairness is the sum of all cookies.
  3. k = len(cookies): The minimum unfairness is the maximum value in the cookies array.
  4. Large cookie values: The sum of cookie values can be large, so binary search is efficient.