Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1862. Sum of Floored Pairs - Leetcode Solution

Problem Description

You are given an array of positive integers nums. The task is to compute the sum of floor(nums[i] / nums[j]) for all pairs (i, j) where 0 ≤ i, j < n and floor(x) is the greatest integer less than or equal to x.

In other words, for every ordered pair of elements in nums, calculate the integer division of nums[i] by nums[j], sum up all these values, and return the result modulo 109 + 7.

  • Each pair (i, j) is considered, including when i == j.
  • Constraints:
    • 1 ≤ nums.length ≤ 105
    • 1 ≤ nums[i] ≤ 105
  • Return the sum modulo 109 + 7.

Thought Process

At first glance, the problem invites a brute-force approach: for every pair of elements in nums, compute floor(nums[i] / nums[j]) and sum the results. However, with up to 10^5 elements, this would require 10^{10} operations—far too slow.

The key is to observe that the same value may appear many times in nums, and the result of floor(a / b) only depends on the values of a and b, not their positions. Thus, grouping by value and precomputing frequencies can help.

We can also flip the problem: instead of iterating over all pairs, for each possible value of nums[j] (call it x), count how many nums[i] fall into each interval where floor(nums[i] / x) = k for each k. This leads to a counting-based, interval-sweeping approach.

This shift—from pairwise iteration to value-based grouping and prefix sums—enables a much faster solution.

Solution Approach

  • Step 1: Frequency Counting
    • Count how many times each value appears in nums. Store this in an array freq of length max(nums) + 1.
  • Step 2: Prefix Sums
    • Build a prefix sum array prefix where prefix[i] is the total number of elements ≤ i in nums.
    • This allows fast queries: for any interval [l, r], prefix[r] - prefix[l-1] gives the count of elements in that range.
  • Step 3: For Each Possible Divisor
    • Iterate over each possible value x that appears in nums (where freq[x] > 0).
    • For each x, consider all possible quotients k such that floor(a / x) = k.
    • For a given x and k, all a in [k*x, (k+1)*x - 1] will have floor(a / x) = k.
    • Use prefix sums to count how many a in nums fall into this interval.
    • Add freq[x] * count * k to the answer.
  • Step 4: Aggregate and Modulo
    • Sum all contributions and return the answer modulo 10^9 + 7.

This approach reduces the time complexity to roughly O(N \log N), which is efficient enough for the problem constraints.

Example Walkthrough

Consider nums = [2, 5, 9]. Let's walk through the optimized solution:

  1. Frequency: freq[2]=1, freq[5]=1, freq[9]=1 (others 0)
  2. Prefix Sum:
    • prefix[2]=1, prefix[5]=2, prefix[9]=3
    • All other prefix[i] are filled accordingly.
  3. For x=2:
    • k=1: range [2,3], count = prefix[3]-prefix[1]=1-0=1
    • k=2: range [4,5], count = prefix[5]-prefix[3]=2-1=1
    • k=3: range [6,7], count = prefix[7]-prefix[5]=2-2=0
    • k=4: range [8,9], count = prefix[9]-prefix[7]=3-2=1
    • Add: freq[2] * (1*1 + 1*2 + 0*3 + 1*4) = 1+2+0+4=7
  4. For x=5:
    • k=1: range [5,9], count = prefix[9]-prefix[4]=3-1=2
    • Add: freq[5] * (2*1) = 2
  5. For x=9:
    • k=1: range [9,9], count = prefix[9]-prefix[8]=3-2=1
    • Add: freq[9] * (1*1) = 1
  6. Total: 7 + 2 + 1 = 10

This matches the expected answer.

Time and Space Complexity

  • Brute-force:
    • Time: O(N^2) — For each pair, compute floor(a / b).
    • Space: O(1) (apart from input and output).
  • Optimized (prefix sum + counting):
    • Time: O(N \log N) (or O(N \sqrt{M}) where M is max value in nums), since for each unique value we process its multiples.
    • Space: O(M) for frequency and prefix sum arrays.

The optimized method is efficient enough for large inputs.

Summary

The Sum of Floored Pairs problem can be solved efficiently by shifting from naive pairwise iteration to a counting strategy using frequency and prefix sums. By grouping elements and using interval sweeps, we avoid redundant calculations and achieve a scalable solution. This approach is a great example of how mathematical insight and careful precomputation can turn an intractable brute-force problem into an elegant and efficient algorithm.

Code Implementation

class Solution:
    def sumOfFlooredPairs(self, nums):
        MOD = 10 ** 9 + 7
        max_num = max(nums)
        freq = [0] * (max_num + 2)
        for num in nums:
            freq[num] += 1

        prefix = [0] * (max_num + 2)
        for i in range(1, max_num + 2):
            prefix[i] = prefix[i - 1] + freq[i]

        ans = 0
        for x in range(1, max_num + 1):
            if freq[x] == 0:
                continue
            k = 1
            while x * k <= max_num:
                l = x * k
                r = min(x * (k + 1) - 1, max_num)
                count = prefix[r] - prefix[l - 1]
                ans = (ans + freq[x] * count * k) % MOD
                k += 1
        return ans
      
class Solution {
public:
    int sumOfFlooredPairs(vector<int>& nums) {
        const int MOD = 1e9 + 7;
        int max_num = *max_element(nums.begin(), nums.end());
        vector<int> freq(max_num + 2, 0);
        for (int num : nums) freq[num]++;
        vector<int> prefix(max_num + 2, 0);
        for (int i = 1; i <= max_num + 1; ++i) {
            prefix[i] = prefix[i-1] + freq[i];
        }
        long long ans = 0;
        for (int x = 1; x <= max_num; ++x) {
            if (freq[x] == 0) continue;
            for (int k = 1; x * k <= max_num; ++k) {
                int l = x * k;
                int r = min(x * (k + 1) - 1, max_num);
                int count = prefix[r] - prefix[l - 1];
                ans = (ans + 1LL * freq[x] * count * k) % MOD;
            }
        }
        return (int)ans;
    }
};
      
class Solution {
    public int sumOfFlooredPairs(int[] nums) {
        int MOD = 1000000007;
        int maxNum = 0;
        for (int num : nums) maxNum = Math.max(maxNum, num);
        int[] freq = new int[maxNum + 2];
        for (int num : nums) freq[num]++;
        int[] prefix = new int[maxNum + 2];
        for (int i = 1; i <= maxNum + 1; i++) {
            prefix[i] = prefix[i - 1] + freq[i];
        }
        long ans = 0;
        for (int x = 1; x <= maxNum; x++) {
            if (freq[x] == 0) continue;
            int k = 1;
            while (x * k <= maxNum) {
                int l = x * k;
                int r = Math.min(x * (k + 1) - 1, maxNum);
                int count = prefix[r] - prefix[l - 1];
                ans = (ans + 1L * freq[x] * count * k) % MOD;
                k++;
            }
        }
        return (int)ans;
    }
}
      
var sumOfFlooredPairs = function(nums) {
    const MOD = 1e9 + 7;
    let maxNum = Math.max(...nums);
    let freq = new Array(maxNum + 2).fill(0);
    for (let num of nums) freq[num]++;
    let prefix = new Array(maxNum + 2).fill(0);
    for (let i = 1; i <= maxNum + 1; i++) {
        prefix[i] = prefix[i - 1] + freq[i];
    }
    let ans = 0;
    for (let x = 1; x <= maxNum; x++) {
        if (freq[x] === 0) continue;
        let k = 1;
        while (x * k <= maxNum) {
            let l = x * k;
            let r = Math.min(x * (k + 1) - 1, maxNum);
            let count = prefix[r] - prefix[l - 1];
            ans = (ans + freq[x] * count * k) % MOD;
            k++;
        }
    }
    return ans;
};