By Vivek - April 19, 2020

Find the Smallest Divisor Given a Threshold in Python

This guide solves the “Find the Smallest Divisor Given a Threshold” problem in Python. The key observation is that the answer is monotonic: as the divisor gets larger, the rounded-up sum gets smaller or stays the same. That makes binary search a good fit.

Table of Contents

  1. Problem
  2. Constraints
  3. Binary search explanation
  4. Python solution
  5. Complexity
  6. Common mistakes
  7. Related Python guides

Problem:

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

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

It is guaranteed that there will be an answer.

Input: nums = [1,2,5,9], threshold = 6

Output: 5

Explanation:
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 to 7 (1+1+2+3) and if the divisor is 5 the sum will be 5 (1+1+1+2).

Constraints:

1 <= nums.length <= 5 * 10^4

1 <= nums[i] <= 10^6

nums.length <= threshold <= 10^6

Binary Search Explanation

  • We need to find the smallest divisor such that the sum of nums is less than the threshold.
  • The minimum value of the divisor can be 1 in that case sum of nums will remain the same whereas the maximum value of the divisor can be the maximum value in nums that will result in a minimum sum
  • Basically, the value of the divisor will be in the range 1 to max(nums)
  • Now we just need to check for every value in this range
  • This problem can be solved by applying a binary search to get the optimal value of the divisor.

The check function answers one question: “Is this divisor small enough to satisfy the threshold?” If the answer is yes, try a smaller divisor. If the answer is no, move to a larger divisor.

Python Solution:

import math
from typing import List

class Solution:
    def smallestDivisor(self, nums: List[int], threshold: int) -> int:
        def check(mid):
            result = 0
            for num in nums:
                result += math.ceil(num / mid)
                if result > threshold:
                	return False
            return True

        left = 1
        right = max(nums)
        while left <= right:
            mid = (left + right) // 2
            if check(mid):
            	right = mid - 1
            else:
            	left = mid + 1
        return left

Complexity

  • Time complexity: O(n log m), where n is the number of values and m is max(nums).
  • Space complexity: O(1), not counting the input array.

Common Mistakes

Using normal division without ceiling

The problem requires each division result to be rounded up. Use math.ceil(num / mid) or integer arithmetic like (num + mid - 1) // mid.

Returning right instead of left

With this binary search shape, left is the first divisor that satisfies the threshold after the loop ends.

Searching past max(nums)

The largest useful divisor is max(nums), because every number then contributes at most 1 to the sum.

Related Python Guides