LeetCode 1862 - Sum of Floored Pairs
The problem asks us to calculate the sum of the integer division results, floor(nums[i] / nums[j]), for every pair of elements (i, j) in a given array nums. Here, floor() represents the largest integer less than or equal to the division result.
Difficulty: 🔴 Hard
Topics: Array, Math, Binary Search, Counting, Enumeration, Prefix Sum
Solution
Problem Understanding
The problem asks us to calculate the sum of the integer division results, floor(nums[i] / nums[j]), for every pair of elements (i, j) in a given array nums. Here, floor() represents the largest integer less than or equal to the division result. The array nums can have up to 10^5 elements, and each element can also be as large as 10^5. Since the total number of pairs is n^2, a naive computation could lead to 10^10 operations, which is infeasible.
The input nums is simply a list of positive integers. The expected output is the sum of all floored divisions for every pair, modulo 10^9 + 7. This modulo ensures that extremely large sums can be handled without integer overflow.
Important edge cases include arrays where all numbers are the same, arrays with only one element, and arrays with elements of varying magnitudes that could produce divisions resulting in zero. The constraints guarantee that the input is non-empty and contains only positive integers, which simplifies handling divisions by zero.
Approaches
The brute-force approach is straightforward: iterate through every pair (i, j), compute floor(nums[i] / nums[j]), and sum the results. This is correct because it directly follows the problem definition, but it is far too slow for the input limits, since it requires O(n^2) operations.
The optimal approach leverages the observation that if we know how many elements fall into certain ranges, we can compute contributions of nums[i] to the sum in batches rather than individually. Specifically, for a fixed nums[j] = x, the value floor(nums[i] / x) only changes at multiples of x. If we precompute the frequency of each number, we can efficiently sum contributions for ranges of nums[i] rather than for each individual element.
We can also use prefix sums or a count array to quickly calculate how many numbers fall within a given range of multiples, which reduces the time complexity dramatically.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n^2) | O(1) | Directly iterate over all pairs |
| Optimal | O(n * maxNum) | O(maxNum) | Use counting and prefix sums to batch contributions |
Algorithm Walkthrough
- Identify the maximum number
maxNuminnumsto define the range for counting frequencies. - Create a frequency array
countof sizemaxNum + 1, wherecount[x]stores how many timesxappears innums. - Build a prefix sum array
prefixfrom the frequency array, whereprefix[i]represents the number of elements innumsless than or equal toi. - Initialize
result = 0to accumulate the sum. - For each
xinnums, compute the contribution ofxfor all multiples ofxup tomaxNum. For a given multiplek*x, the number of elementsnums[i]in the range[k*x, (k+1)*x - 1]contributeskto the sum. Use the prefix array to quickly count how many elements fall in that range. - Add the computed contribution to
result, taking modulo10^9 + 7. - Return
result.
Why it works: By iterating over multiples of each number and using prefix sums to count elements efficiently, the algorithm ensures that every pair (i, j) is accounted for without redundant computation. The contribution of each number is correctly weighted by the integer division result.
Python Solution
from typing import List
class Solution:
def sumOfFlooredPairs(self, nums: List[int]) -> int:
MOD = 10**9 + 7
max_num = max(nums)
count = [0] * (max_num + 1)
for num in nums:
count[num] += 1
prefix = [0] * (max_num + 2)
for i in range(1, max_num + 1):
prefix[i] = prefix[i - 1] + count[i]
result = 0
for x in nums:
k = 1
while k * x <= max_num:
left = k * x
right = min(max_num, (k + 1) * x - 1)
contribution = k * (prefix[right] - prefix[left - 1])
result = (result + contribution) % MOD
k += 1
return result
The Python implementation first calculates the frequency of each number and then builds the prefix sum. For each element, it sums contributions over ranges defined by multiples of the element. Modulo is applied at each step to prevent overflow.
Go Solution
func sumOfFlooredPairs(nums []int) int {
const MOD = 1_000_000_007
maxNum := 0
for _, num := range nums {
if num > maxNum {
maxNum = num
}
}
count := make([]int, maxNum+1)
for _, num := range nums {
count[num]++
}
prefix := make([]int, maxNum+2)
for i := 1; i <= maxNum; i++ {
prefix[i] = prefix[i-1] + count[i]
}
result := 0
for _, x := range nums {
k := 1
for k*x <= maxNum {
left := k * x
right := (k+1)*x - 1
if right > maxNum {
right = maxNum
}
contribution := k * (prefix[right] - prefix[left-1])
result = (result + contribution) % MOD
k++
}
}
return result
}
The Go implementation mirrors the Python approach. Arrays are initialized for counting and prefix sums. Care is taken to ensure array bounds are correct, and integer overflow is avoided using modulo.
Worked Examples
Example 1: nums = [2,5,9]
- maxNum = 9
- count = [0,0,1,0,0,1,0,0,0,1]
- prefix = [0,0,1,1,1,2,2,2,2,3,3]
- For x = 2:
- k = 1: range [2,3] → contribution = 1*(prefix[3]-prefix[1]) = 1*(1-0)=1
- k = 2: range [4,5] → contribution = 2*(prefix[5]-prefix[3]) = 2*(2-1)=2
- k = 3: range [6,7] → contribution = 3*(prefix[7]-prefix[5]) = 3*(2-2)=0
- k = 4: range [8,9] → contribution = 4*(prefix[9]-prefix[7]) = 4*(3-2)=4
- Repeat for x = 5 and x = 9, summing contributions = 10
Example 2: nums = [7,7,7,7,7,7,7]
- Each element contributes 7 pairs with floor division 1. Total sum = 7*7 = 49
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n + n * sqrt(maxNum))) | Counting and prefix sum O(n + maxNum), contributions are bounded by multiples ≤ maxNum |
| Space | O(maxNum) | Arrays for counting and prefix sums |
The time complexity is much lower than brute-force because we aggregate contributions via multiples rather than iterating over all pairs.
Test Cases
# provided examples
assert Solution().sumOfFlooredPairs([2,5,9]) == 10 # Example 1
assert Solution().sumOfFlooredPairs([7,7,7,7,7,7,7]) == 49 # Example 2
# edge cases
assert Solution().sumOfFlooredPairs([1]) == 1 # single element
assert Solution().sumOfFlooredPairs([1,2,3]) == 5 # small varied elements
assert Solution().sumOfFlooredPairs([100000]*5) == 25 # max element repeated
assert Solution().sumOfFlooredPairs([1,100000]) == 2 # extreme difference
| Test | Why |
|---|---|
| [2,5,9] | Standard case with mixed numbers |
| [7,7,7,7,7,7,7] | All elements equal |
| [1] | Single element array |
| [1,2,3] | Small varied numbers to check floor calculation |
| [100000]*5 | Large repeated numbers to check efficiency |
| [1,100000] | Extreme difference to test contribution counting |
Edge Cases
Single Element Array: The only element divides itself, yielding 1. This ensures the code correctly handles the lower bound.
All Elements Equal: Every division yields 1, which is simple but tests summing of repeated values.
Maximum Value Elements: When elements are at 10^5, the code must handle large numbers without exceeding array bounds or integer limits. Prefix sums and modulo prevent overflow