Taro Logo

Find the Smallest Divisor Given a Threshold

Medium
Google logo
Google
Topics:
ArraysBinary Search

Given an array of integers nums and an integer threshold, we will choose a positive integer divisor, divide all the array by it, and sum the division's result. Find the smallest divisor such that the result mentioned above is less than or equal to threshold.

Each result of the division is rounded to the nearest integer greater than or equal to that element. (For example: 7/3 = 3 and 10/2 = 5).

For example: nums = [1,2,5,9], threshold = 6. The output is 5. We can get a sum to 17 (1+2+5+9) if the divisor is 1. If the divisor is 4 we can get a sum of 7 (1+1+2+3) and if the divisor is 5 the sum will be 5 (1+1+1+2).

As another example, nums = [44,22,33,11,1], threshold = 5. The output is 44.

What is the most efficient way to solve this problem?

Solution


Naive Solution

A brute-force approach would be to iterate through all possible divisors starting from 1 up to the maximum value in the nums array. For each divisor, calculate the sum of the ceiling of each number divided by the divisor. If the sum is less than or equal to the threshold, return that divisor. Since we want the smallest divisor, we can stop and return the first divisor that satisfies the condition.

Code (Python)

def solve(nums, threshold):
 max_num = max(nums)
 for divisor in range(1, max_num + 1):
 sum_val = 0
 for num in nums:
 sum_val += (num + divisor - 1) // divisor  # Ceiling division
 if sum_val <= threshold:
 return divisor
 return -1 # Should not reach here based on problem constraints

Time Complexity

O(M * N), where M is the maximum value in nums and N is the length of nums. We iterate up to max(nums) and for each potential divisor, iterate through nums.

Space Complexity

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

Optimal Solution: Binary Search

Since the problem statement guarantees that a solution exists, and the divisor must be between 1 and the maximum element in nums, we can use binary search to efficiently find the smallest divisor that satisfies the condition. The search space is the range [1, max(nums)].

Algorithm

  1. Initialize left to 1 and right to the maximum element in nums.
  2. While left < right, calculate mid = left + (right - left) // 2.
  3. Calculate the sum of divisions using mid as the divisor.
  4. If the sum is greater than threshold, the divisor is too small. Update left = mid + 1.
  5. Otherwise, the divisor is feasible. Update right = mid to search for an even smaller divisor.
  6. When left == right, left (or right) is the smallest divisor that satisfies the condition.

Code (Python)

def solve_optimal(nums, threshold):
 left = 1
 right = max(nums)
 while left < right:
 mid = left + (right - left) // 2
 sum_val = 0
 for num in nums:
 sum_val += (num + mid - 1) // mid
 if sum_val > threshold:
 left = mid + 1
 else:
 right = mid
 return left

Time Complexity

O(N * log(M)), where N is the length of nums and M is the maximum value in nums. We perform binary search on the range [1, max(nums)], and for each potential divisor, we iterate through nums to calculate the sum of divisions.

Space Complexity

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

Edge Cases

  • Empty Array: The problem statement specifies 1 <= nums.length, so we don't need to handle an empty input array.
  • Single Element Array: The algorithm works correctly even when nums has only one element.
  • Threshold Equal to Array Length: If the threshold is equal to the length of the array, it means each element divided by the divisor should ideally be 1. So, the divisor should be greater than or equal to all the numbers in the array. Thus the maximum number will be the answer
  • All elements are 1: If the array only contains ones, the answer will be the ceiling of len(nums)/threshold