Facebook Pixel

3712. Sum of Elements With Frequency Divisible by K

EasyArrayHash TableCounting
LeetCode ↗

Problem Description

You are given an integer array nums and an integer k.

Your task is to return the sum of all elements in nums whose frequency (the number of times they appear in the array) is divisible by k. If no such elements exist, return 0.

Important detail: When an element qualifies (i.e., its total frequency is divisible by k), it contributes to the sum exactly as many times as it appears in the array — not just once.

For example, if nums = [1, 2, 2, 3, 3, 3] and k = 2:

  • The number 1 appears 1 time — 1 % 2 != 0, so it is excluded.
  • The number 2 appears 2 times — 2 % 2 == 0, so it contributes 2 + 2 = 4.
  • The number 3 appears 3 times — 3 % 2 != 0, so it is excluded.

The answer would be 4.

In short, the problem breaks down into three steps:

  1. Count how many times each number appears in nums.
  2. Check which numbers have a frequency divisible by k.
  3. Sum up those numbers, multiplied by their frequencies (i.e., x * cnt[x] for each qualifying number x).
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Hash Table / Counting?

This problem maps to Hash Table / Counting through a short path in the full flowchart.

Linkedlist?noFastlookup,counting,yesHash Table /Counting

The deciding value is each number's frequency, so we count occurrences in a hash table before summing the qualifying values.

Open in Flowchart

Intuition

The problem revolves entirely around one piece of information: how many times each number appears in the array. Without knowing the frequency of a number, we cannot decide whether it should be included in the sum. So the natural first thought is — count everything first, then decide.

This immediately points to using a hash table (or Counter in Python), which is the standard tool for frequency counting. One pass through nums gives us a complete mapping from each distinct number x to its frequency cnt[x].

Once the counts are available, the decision for each number becomes a simple check: is cnt[x] % k == 0?

The other key observation comes from the note in the problem: a qualifying element is counted as many times as it appears, not just once. Rather than adding x repeatedly cnt[x] times, we can capture all of its occurrences in a single multiplication — x * cnt[x]. This turns the final step into a clean aggregation:

  • For each distinct number x with frequency v, if v % k == 0, add x * v to the answer.

So the approach falls out naturally from two ideas:

  1. Frequency is the deciding factor → count occurrences with a hash table.
  2. Each occurrence contributes to the sum → multiply the value by its frequency instead of summing duplicates one by one.

This gives a straightforward solution that runs in O(n) time with O(n) extra space, where n is the length of nums — a single pass to count, and a single pass over the distinct values to sum.

Solution Approach

Pattern used: Counting with a hash table.

The implementation follows two simple phases — count, then aggregate.

Step 1: Count the frequency of each number

We use a hash table cnt to record how many times each number appears:

cnt = Counter(nums)

Counter(nums) traverses the array once. For each number x, it increments cnt[x] by 1. After this pass, cnt maps every distinct value in nums to its total frequency. This is equivalent to writing:

cnt = {}
for x in nums:
    cnt[x] = cnt.get(x, 0) + 1

Step 2: Sum the qualifying elements

Next, we traverse the hash table. For each entry (x, v) — where x is the number and v is its frequency — we check whether v is divisible by k:

  • If v % k == 0, the number qualifies. Since it must be counted once per occurrence, it contributes x * v to the total.
  • Otherwise, it contributes nothing.

This is expressed compactly with a generator expression:

return sum(x * v for x, v in cnt.items() if v % k == 0)

If no element satisfies the condition, the generator yields nothing and sum returns 0, which matches the required default — no special-case handling is needed.

Full Code

class Solution:
    def sumDivisibleByK(self, nums: List[int], k: int) -> int:
        cnt = Counter(nums)
        return sum(x * v for x, v in cnt.items() if v % k == 0)

Walkthrough Example

Take nums = [1, 2, 2, 3, 3, 3, 3] and k = 2:

  1. Counting gives cnt = {1: 1, 2: 2, 3: 4}.
  2. Checking each entry:
    • 1 has frequency 11 % 2 != 0 → skipped.
    • 2 has frequency 22 % 2 == 0 → contributes 2 * 2 = 4.
    • 3 has frequency 44 % 2 == 0 → contributes 3 * 4 = 12.
  3. Final answer: 4 + 12 = 16.

Complexity Analysis

  • Time complexity: O(n), where n is the length of nums. One pass to build the counter and one pass over at most n distinct keys.
  • Space complexity: O(n) in the worst case, when all elements in nums are distinct and the hash table stores n entries.

Alternative Perspective

A sorting-based approach is also possible: sort the array, scan groups of equal values, and add each group's total x * groupSize when groupSize % k == 0. This reduces extra space to O(1) (ignoring sort space) but raises time to O(n log n), making the hash table approach the better default choice.

Example Walkthrough

Let's trace the solution with nums = [3, 3, 1, 1, 1, 1, 5] and k = 2.

Step 1: Build the frequency table

Counter(nums) scans the array once, updating counts element by element:

Element readcnt after update
3{3: 1}
3{3: 2}
1{3: 2, 1: 1}
1{3: 2, 1: 2}
1{3: 2, 1: 3}
1{3: 2, 1: 4}
5{3: 2, 1: 4, 5: 1}

Final table: cnt = {3: 2, 1: 4, 5: 1}.

Step 2: Aggregate the qualifying entries

Now iterate over each (x, v) pair and test v % k == 0:

xv (frequency)v % 2Qualifies?Contribution x * vRunning sum
320✅ Yes3 * 2 = 66
140✅ Yes1 * 4 = 410
511❌ No10

Result: 10

Notice two key behaviors confirmed by this trace:

  • The element 3 appears twice and contributes both occurrences (6, not 3) — the multiplication x * v handles repetition without looping over duplicates.
  • The element 5 is filtered out entirely because its frequency 1 is not divisible by 2.

As a sanity check for the edge case: if we ran the same array with k = 5, no frequency (2, 4, or 1) is divisible by 5, the generator expression yields nothing, and sum naturally returns 0 — exactly the required default, with no extra code.

Solution Implementation

1class Solution:
2    def sumDivisibleByK(self, nums: List[int], k: int) -> int:
3        # Count the occurrences of each number in nums
4        counter = Counter(nums)
5        # Sum up numbers whose occurrence count is divisible by k,
6        # multiplying each number by its occurrence count
7        return sum(num * count for num, count in counter.items() if count % k == 0)
8```
9
10**Explanation:**
11
121. **Counting occurrences:** `Counter(nums)` builds a hash map where each key is a number from `nums` and each value is how many times it appears.
13
142. **Filtering and summing:** The generator expression iterates over each `(num, count)` pair:
15   - The condition `count % k == 0` keeps only numbers whose occurrence count is divisible by `k`.
16   - For each qualifying number, `num * count` adds up **all** its occurrences (not just the number once).
17
183. **Complexity:**
19   - Time: `O(n)` — one pass to count, one pass over distinct elements.
20   - Space: `O(n)` — for the counter in the worst case (all elements distinct).
21
22**Alternative perspective:** If you prefer avoiding `Counter`, a plain dictionary works equally well:
23
24```python3
25class Solution:
26    def sumDivisibleByK(self, nums: List[int], k: int) -> int:
27        # Manually count occurrences with a dictionary
28        counter = {}
29        for num in nums:
30            counter[num] = counter.get(num, 0) + 1
31        # Accumulate the total for numbers whose count is divisible by k
32        total = 0
33        for num, count in counter.items():
34            if count % k == 0:
35                total += num * count
36        return total
37
1class Solution {
2    public int sumDivisibleByK(int[] nums, int k) {
3        // Map to store the frequency of each number in the array
4        Map<Integer, Integer> frequencyMap = new HashMap<>();
5
6        // Count occurrences of each number
7        for (int num : nums) {
8            frequencyMap.merge(num, 1, Integer::sum);
9        }
10
11        int answer = 0;
12
13        // Iterate over each unique number and its frequency
14        for (Map.Entry<Integer, Integer> entry : frequencyMap.entrySet()) {
15            int number = entry.getKey();
16            int frequency = entry.getValue();
17
18            // If the frequency is divisible by k, add the total contribution
19            // of this number (number * frequency) to the answer
20            if (frequency % k == 0) {
21                answer += number * frequency;
22            }
23        }
24
25        return answer;
26    }
27}
28
1class Solution {
2public:
3    int sumDivisibleByK(vector<int>& nums, int k) {
4        // Map to store the frequency of each number in nums
5        unordered_map<int, int> countMap;
6
7        // Count the occurrences of each number
8        for (int num : nums) {
9            ++countMap[num];
10        }
11
12        int answer = 0;
13
14        // Iterate over each unique number and its frequency
15        for (auto& [num, frequency] : countMap) {
16            // If the frequency is divisible by k,
17            // add the total contribution (num * frequency) to the answer
18            if (frequency % k == 0) {
19                answer += num * frequency;
20            }
21        }
22
23        return answer;
24    }
25};
26
1/**
2 * Calculates the sum of all elements whose occurrence count
3 * is divisible by k.
4 *
5 * @param nums - The input array of numbers
6 * @param k - The divisor used to check occurrence counts
7 * @returns The total sum of qualifying elements (value * count)
8 */
9function sumDivisibleByK(nums: number[], k: number): number {
10    // Map to store the frequency of each number in the array
11    const countMap: Map<number, number> = new Map<number, number>();
12
13    // Count the occurrences of each number
14    for (const num of nums) {
15        countMap.set(num, (countMap.get(num) ?? 0) + 1);
16    }
17
18    // Accumulator for the final result
19    let answer: number = 0;
20
21    // Iterate over each unique number and its frequency
22    for (const [num, count] of countMap.entries()) {
23        // If the frequency is divisible by k, add the total contribution
24        if (count % k === 0) {
25            answer += num * count;
26        }
27    }
28
29    return answer;
30}
31

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the array nums. Building the counter with Counter(nums) requires a single pass over all n elements, and the subsequent summation iterates over at most n distinct keys.

  • Space Complexity: O(m), where m is the number of distinct elements in the array nums. The Counter stores one entry per distinct element, so the extra space grows with the number of unique values rather than the total length of the array.

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Adding each qualifying number only once instead of once per occurrence

The most frequent mistake is summing num instead of num * count. The problem explicitly requires that a qualifying element contributes as many times as it appears in the array.

Incorrect code:

class Solution:
    def sumDivisibleByK(self, nums: List[int], k: int) -> int:
        counter = Counter(nums)
        # WRONG: adds each qualifying number just once
        return sum(num for num, count in counter.items() if count % k == 0)

Why it fails: For nums = [1, 2, 2, 3, 3, 3] and k = 2, the number 2 appears twice, so it should contribute 2 + 2 = 4. The incorrect code returns 2 instead.

Fix: Multiply each qualifying number by its frequency:

return sum(num * count for num, count in counter.items() if count % k == 0)

Pitfall 2: Checking divisibility in the wrong direction

It is easy to accidentally write k % count == 0 instead of count % k == 0. The condition must verify that the frequency is divisible by k, not the other way around.

Incorrect code:

if k % count == 0:  # WRONG: tests whether k is divisible by the frequency
    total += num * count

Why it fails: For nums = [5, 5, 5, 5] and k = 2, the frequency of 5 is 4. The correct check 4 % 2 == 0 passes, but the reversed check 2 % 4 == 0 fails, producing 0 instead of 20. Worse, if some element's frequency happens to divide k (e.g., frequency 1), the reversed check wrongly includes it.

Fix: Always test count % k == 0.

Pitfall 3: Filtering while iterating over the raw array instead of the counter

Some implementations try to do everything in a single pass over nums, checking the running count as they go. The running count is not the final frequency, so the decision is made with incomplete information.

Incorrect code:

class Solution:
    def sumDivisibleByK(self, nums: List[int], k: int) -> int:
        counter = {}
        total = 0
        for num in nums:
            counter[num] = counter.get(num, 0) + 1
            # WRONG: the count here is partial, not the final frequency
            if counter[num] % k == 0:
                total += num
        return total

Why it fails: For nums = [3, 3, 3] and k = 2, the running count of 3 hits 2 midway, so 3 is added — but its final frequency is 3, which is not divisible by 2. The correct answer is 0, yet this code returns 3.

Fix: Complete the counting phase first, then make decisions based on the final frequencies:

counter = Counter(nums)
return sum(num * count for num, count in counter.items() if count % k == 0)

A correct single-pass-over-nums variant does exist — iterate over nums a second time and add num whenever counter[num] % k == 0 — but counting must still be fully finished before any element is judged.

Pitfall 4: Assuming k could relate to the element values rather than frequencies

A careless reading may lead to filtering by num % k == 0 (the value divisible by k) instead of the frequency being divisible by k. Re-read the problem: divisibility applies to how many times the element appears, never to the element itself. Negative values in nums are perfectly fine and require no special handling, since only frequencies (always positive) interact with k.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More