Problem

You are given an integer array nums of length n and an integer array queries.

Let gcdPairs denote an array obtained by calculating the GCD of all possible pairs (nums[i], nums[j]), where 0 <= i < j < n, and then sorting these values in ascending order.

For each query queries[i], you need to find the element at index queries[i] in gcdPairs.

Return an integer array answer, where answer[i] is the value at gcdPairs[queries[i]] for each query.

The term gcd(a, b) denotes the greatest common divisor of a and b.

Examples

Example 1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

Input: nums = [2,3,4], queries = [0,2,2]

Output: [1,2,2]

Explanation:

`gcdPairs = [gcd(nums[0], nums[1]), gcd(nums[0], nums[2]), gcd(nums[1],
nums[2])] = [1, 2, 1]`.

After sorting in ascending order, `gcdPairs = [1, 1, 2]`.

So, the answer is `[gcdPairs[queries[0]], gcdPairs[queries[1]],
gcdPairs[queries[2]]] = [1, 2, 2]`.

Example 2

1
2
3
4
5
6
7
8

Input: nums = [4,4,2,1], queries = [5,3,1,0]

Output: [4,2,1,1]

Explanation:

`gcdPairs` sorted in ascending order is `[1, 1, 1, 2, 2, 4]`.

Example 3

1
2
3
4
5
6
7
8

Input: nums = [2,2], queries = [0,0]

Output: [2,2]

Explanation:

`gcdPairs = [2]`.

Constraints

  • 2 <= n == nums.length <= 10^5
  • 1 <= nums[i] <= 5 * 10^4
  • 1 <= queries.length <= 10^5
  • 0 <= queries[i] < n * (n - 1) / 2

Solution

Method 1 - Counting with Möbius Function

Intuition Instead of generating all O(n²) pairs, we count how many pairs have each possible GCD value. We use number theory (Möbius function) to efficiently count pairs with specific GCD values.

Approach

  1. Count frequency of each number in nums
  2. For each possible GCD value g, count how many pairs have GCD exactly equal to g
  3. Use inclusion-exclusion principle with Möbius function to avoid overcounting
  4. Build prefix sum array to answer queries in O(1)
  5. Use binary search to find the answer for each query

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

vector<int> gcdValues(vector<int>& nums, vector<long long>& queries) {
    int maxVal = *max_element(nums.begin(), nums.end());
    
    // Count frequency of each number
    vector<int> freq(maxVal + 1, 0);
    for (int num : nums) {
        freq[num]++;
    }
    
    // Count how many numbers are divisible by each divisor
    vector<long long> divisorCount(maxVal + 1, 0);
    for (int d = 1; d <= maxVal; d++) {
        for (int multiple = d; multiple <= maxVal; multiple += d) {
            divisorCount[d] += freq[multiple];
        }
    }
    
    // Count pairs with GCD exactly equal to g using inclusion-exclusion
    vector<long long> gcdCount(maxVal + 1, 0);
    for (int g = maxVal; g >= 1; g--) {
        long long cnt = divisorCount[g];
        gcdCount[g] = cnt * (cnt - 1) / 2; // Choose 2 from cnt numbers
        
        // Subtract pairs with GCD > g (inclusion-exclusion)
        for (int multiple = 2 * g; multiple <= maxVal; multiple += g) {
            gcdCount[g] -= gcdCount[multiple];
        }
    }
    
    // Build prefix sum for binary search
    vector<long long> prefixSum;
    for (int g = 1; g <= maxVal; g++) {
        if (gcdCount[g] > 0) {
            for (long long i = 0; i < gcdCount[g]; i++) {
                prefixSum.push_back(g);
            }
        }
    }
    
    vector<int> result;
    for (long long query : queries) {
        result.push_back(prefixSum[query]);
    }
    
    return result;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import "sort"

func gcdValues(nums []int, queries []int64) []int {
    maxVal := 0
    for _, num := range nums {
        if num > maxVal {
            maxVal = num
        }
    }
    
    // Count frequency
    freq := make([]int, maxVal+1)
    for _, num := range nums {
        freq[num]++
    }
    
    // Count divisor occurrences
    divisorCount := make([]int64, maxVal+1)
    for d := 1; d <= maxVal; d++ {
        for multiple := d; multiple <= maxVal; multiple += d {
            divisorCount[d] += int64(freq[multiple])
        }
    }
    
    // Count GCD pairs using inclusion-exclusion
    gcdCount := make([]int64, maxVal+1)
    for g := maxVal; g >= 1; g-- {
        cnt := divisorCount[g]
        gcdCount[g] = cnt * (cnt - 1) / 2
        
        for multiple := 2 * g; multiple <= maxVal; multiple += g {
            gcdCount[g] -= gcdCount[multiple]
        }
    }
    
    // Build sorted list
    var prefixSum []int
    for g := 1; g <= maxVal; g++ {
        for i := int64(0); i < gcdCount[g]; i++ {
            prefixSum = append(prefixSum, g)
        }
    }
    
    result := make([]int, len(queries))
    for i, query := range queries {
        result[i] = prefixSum[query]
    }
    
    return result
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.*;

class Solution {
    public int[] gcdValues(int[] nums, long[] queries) {
        int maxVal = Arrays.stream(nums).max().getAsInt();
        
        // Count frequency
        int[] freq = new int[maxVal + 1];
        for (int num : nums) {
            freq[num]++;
        }
        
        // Count divisor occurrences
        long[] divisorCount = new long[maxVal + 1];
        for (int d = 1; d <= maxVal; d++) {
            for (int multiple = d; multiple <= maxVal; multiple += d) {
                divisorCount[d] += freq[multiple];
            }
        }
        
        // Count GCD pairs using inclusion-exclusion
        long[] gcdCount = new long[maxVal + 1];
        for (int g = maxVal; g >= 1; g--) {
            long cnt = divisorCount[g];
            gcdCount[g] = cnt * (cnt - 1) / 2;
            
            for (int multiple = 2 * g; multiple <= maxVal; multiple += g) {
                gcdCount[g] -= gcdCount[multiple];
            }
        }
        
        // Build sorted list
        List<Integer> prefixSum = new ArrayList<>();
        for (int g = 1; g <= maxVal; g++) {
            for (long i = 0; i < gcdCount[g]; i++) {
                prefixSum.add(g);
            }
        }
        
        int[] result = new int[queries.length];
        for (int i = 0; i < queries.length; i++) {
            result[i] = prefixSum.get((int) queries[i]);
        }
        
        return result;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
    fun gcdValues(nums: IntArray, queries: LongArray): IntArray {
        val maxVal = nums.maxOrNull() ?: 0
        
        // Count frequency
        val freq = IntArray(maxVal + 1)
        for (num in nums) {
            freq[num]++
        }
        
        // Count divisor occurrences
        val divisorCount = LongArray(maxVal + 1)
        for (d in 1..maxVal) {
            var multiple = d
            while (multiple <= maxVal) {
                divisorCount[d] += freq[multiple].toLong()
                multiple += d
            }
        }
        
        // Count GCD pairs using inclusion-exclusion
        val gcdCount = LongArray(maxVal + 1)
        for (g in maxVal downTo 1) {
            val cnt = divisorCount[g]
            gcdCount[g] = cnt * (cnt - 1) / 2
            
            var multiple = 2 * g
            while (multiple <= maxVal) {
                gcdCount[g] -= gcdCount[multiple]
                multiple += g
            }
        }
        
        // Build sorted list
        val prefixSum = mutableListOf<Int>()
        for (g in 1..maxVal) {
            repeat(gcdCount[g].toInt()) {
                prefixSum.add(g)
            }
        }
        
        return IntArray(queries.size) { i ->
            prefixSum[queries[i].toInt()]
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def gcdValues(nums: list[int], queries: list[int]) -> list[int]:
    max_val = max(nums)
    
    # Count frequency
    freq = [0] * (max_val + 1)
    for num in nums:
        freq[num] += 1
    
    # Count divisor occurrences
    divisor_count = [0] * (max_val + 1)
    for d in range(1, max_val + 1):
        for multiple in range(d, max_val + 1, d):
            divisor_count[d] += freq[multiple]
    
    # Count GCD pairs using inclusion-exclusion
    gcd_count = [0] * (max_val + 1)
    for g in range(max_val, 0, -1):
        cnt = divisor_count[g]
        gcd_count[g] = cnt * (cnt - 1) // 2
        
        for multiple in range(2 * g, max_val + 1, g):
            gcd_count[g] -= gcd_count[multiple]
    
    # Build sorted list
    prefix_sum = []
    for g in range(1, max_val + 1):
        prefix_sum.extend([g] * gcd_count[g])
    
    return [prefix_sum[query] for query in queries]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
pub fn gcd_values(nums: Vec<i32>, queries: Vec<i64>) -> Vec<i32> {
    let max_val = *nums.iter().max().unwrap() as usize;
    
    // Count frequency
    let mut freq = vec![0; max_val + 1];
    for num in nums {
        freq[num as usize] += 1;
    }
    
    // Count divisor occurrences
    let mut divisor_count = vec![0i64; max_val + 1];
    for d in 1..=max_val {
        let mut multiple = d;
        while multiple <= max_val {
            divisor_count[d] += freq[multiple] as i64;
            multiple += d;
        }
    }
    
    // Count GCD pairs using inclusion-exclusion
    let mut gcd_count = vec![0i64; max_val + 1];
    for g in (1..=max_val).rev() {
        let cnt = divisor_count[g];
        gcd_count[g] = cnt * (cnt - 1) / 2;
        
        let mut multiple = 2 * g;
        while multiple <= max_val {
            gcd_count[g] -= gcd_count[multiple];
            multiple += g;
        }
    }
    
    // Build sorted list
    let mut prefix_sum = Vec::new();
    for g in 1..=max_val {
        for _ in 0..gcd_count[g] {
            prefix_sum.push(g as i32);
        }
    }
    
    queries.iter().map(|&query| prefix_sum[query as usize]).collect()
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function gcdValues(nums: number[], queries: number[]): number[] {
    const maxVal = Math.max(...nums);
    
    // Count frequency
    const freq = new Array(maxVal + 1).fill(0);
    for (const num of nums) {
        freq[num]++;
    }
    
    // Count divisor occurrences
    const divisorCount = new Array(maxVal + 1).fill(0);
    for (let d = 1; d <= maxVal; d++) {
        for (let multiple = d; multiple <= maxVal; multiple += d) {
            divisorCount[d] += freq[multiple];
        }
    }
    
    // Count GCD pairs using inclusion-exclusion
    const gcdCount = new Array(maxVal + 1).fill(0);
    for (let g = maxVal; g >= 1; g--) {
        const cnt = divisorCount[g];
        gcdCount[g] = Math.floor(cnt * (cnt - 1) / 2);
        
        for (let multiple = 2 * g; multiple <= maxVal; multiple += g) {
            gcdCount[g] -= gcdCount[multiple];
        }
    }
    
    // Build sorted list
    const prefixSum: number[] = [];
    for (let g = 1; g <= maxVal; g++) {
        for (let i = 0; i < gcdCount[g]; i++) {
            prefixSum.push(g);
        }
    }
    
    return queries.map(query => prefixSum[query]);
}

Complexity

  • ⏰ Time complexity: O(M log M + Q) where M is the maximum value in nums and Q is the number of queries
  • 🧺 Space complexity: O(M + P) where P is the total number of pairs