Facebook Pixel

3591. Check if Any Element Has Prime Frequency

EasyArrayHash TableMathCountingNumber Theory
Leetcode Link

Problem Description

You are given an integer array nums. Your task is to determine if any element in the array appears a prime number of times.

The problem asks you to:

  1. Count how many times each element appears in the array (this is called the frequency)
  2. Check if any of these frequencies is a prime number
  3. Return true if at least one element has a prime frequency, otherwise return false

A prime number is a natural number greater than 1 that has exactly two factors: 1 and itself. For example, 2, 3, 5, 7, 11 are prime numbers.

Example scenarios:

  • If an element appears 2 times, that's a prime frequency (2 is prime)
  • If an element appears 3 times, that's a prime frequency (3 is prime)
  • If an element appears 4 times, that's not a prime frequency (4 = 2 × 2)
  • If an element appears 1 time, that's not a prime frequency (1 is not prime)

The solution counts the frequency of each element using a Counter, then checks each frequency value to see if it's prime. The helper function is_prime verifies primality by checking if the number has any divisors between 2 and its square root. If any frequency is prime, the function returns true.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem essentially breaks down into two distinct tasks: counting and prime checking.

When we see "frequency of elements," the immediate thought is to use a frequency map or counter to track how many times each element appears. This is a standard pattern - whenever we need to know "how many times" something occurs, we reach for a hash table or counter.

Once we have the frequencies, we need to check if any of them is prime. The key insight here is that we don't care which element has a prime frequency or even how many elements have prime frequencies - we just need to know if at least one exists. This "at least one" requirement naturally leads us to use the any() function, which short-circuits as soon as it finds a prime frequency.

For the prime checking part, we need an efficient way to determine if a number is prime. The classic approach is to check divisibility. We know that:

  • Numbers less than 2 are not prime
  • For any composite number n, it must have at least one divisor less than or equal to sqrt(n)

Why sqrt(n)? Because if n = a × b and both a and b were greater than sqrt(n), then a × b would be greater than n, which is a contradiction. So we only need to check divisors up to sqrt(n).

The beauty of this solution is its simplicity - we're just combining two well-known algorithms: frequency counting with Counter and prime checking with trial division. The any() function elegantly handles the "return true if at least one prime frequency exists" requirement without needing explicit loops or early returns.

Learn more about Math patterns.

Solution Approach

The solution uses Counting + Prime Check as mentioned in the reference approach.

Step 1: Count frequencies using a hash table

We use Python's Counter from the collections module to create a frequency map:

cnt = Counter(nums)

This creates a dictionary where keys are the unique elements from nums and values are their frequencies. For example, if nums = [1, 1, 2, 2, 2], then cnt = {1: 2, 2: 3}.

Step 2: Implement the prime checking function

The helper function is_prime(x) determines if a number is prime:

def is_prime(x: int) -> bool:
    if x < 2:
        return False
    return all(x % i for i in range(2, int(sqrt(x)) + 1))
  • First, we handle the base case: numbers less than 2 are not prime
  • Then we check if x is divisible by any number from 2 to sqrt(x)
  • The all() function returns True if all remainders are non-zero (meaning no divisors found)
  • We use int(sqrt(x)) + 1 as the upper bound to ensure we check all necessary divisors

Step 3: Check if any frequency is prime

Finally, we iterate through all frequency values and check if any is prime:

return any(is_prime(x) for x in cnt.values())

The any() function:

  • Iterates through cnt.values() (the frequencies)
  • Applies is_prime() to each frequency
  • Returns True as soon as it finds a prime frequency (short-circuit evaluation)
  • Returns False if no prime frequencies are found

Time Complexity: O(n + m × sqrt(k)) where n is the length of the array, m is the number of unique elements, and k is the maximum frequency value.

Space Complexity: O(m) for storing the frequency map.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [3, 1, 3, 2, 3, 2, 1].

Step 1: Count frequencies First, we count how many times each element appears:

  • Element 1 appears 2 times
  • Element 2 appears 2 times
  • Element 3 appears 3 times

So our frequency map is: {3: 3, 1: 2, 2: 2}

Step 2: Check each frequency for primality Now we check if any of these frequencies (3, 2, 2) is prime:

For frequency 3:

  • Is 3 < 2? No
  • Check divisors from 2 to √3 ≈ 1.73, so we check only 2
  • Is 3 divisible by 2? No (3 % 2 = 1)
  • Since no divisors found, 3 is prime ✓

Since we found a prime frequency (3), we can stop here and return true.

Note that if we continued checking:

  • Frequency 2 is also prime (only divisible by 1 and 2)
  • But we don't need to check further since any() short-circuits after finding the first prime

Result: Return true because element 3 appears a prime number of times (3 times).


Another example: nums = [1, 1, 1, 1]

Step 1: Count frequencies → {1: 4}

Step 2: Check if 4 is prime:

  • Is 4 < 2? No
  • Check divisors from 2 to √4 = 2
  • Is 4 divisible by 2? Yes (4 % 2 = 0)
  • Since we found a divisor, 4 is not prime

Result: Return false because no element has a prime frequency.

Solution Implementation

1from typing import List
2from collections import Counter
3from math import sqrt
4
5class Solution:
6    def checkPrimeFrequency(self, nums: List[int]) -> bool:
7        """
8        Check if any element in the array appears a prime number of times.
9      
10        Args:
11            nums: List of integers to check
12          
13        Returns:
14            True if at least one element appears a prime number of times, False otherwise
15        """
16      
17        def is_prime(n: int) -> bool:
18            """
19            Determine if a number is prime.
20          
21            Args:
22                n: Integer to check for primality
23              
24            Returns:
25                True if n is prime, False otherwise
26            """
27            # Numbers less than 2 are not prime
28            if n < 2:
29                return False
30          
31            # Check divisibility from 2 to sqrt(n)
32            # If n is divisible by any number in this range, it's not prime
33            for i in range(2, int(sqrt(n)) + 1):
34                if n % i == 0:
35                    return False
36          
37            return True
38      
39        # Count the frequency of each element in the array
40        frequency_map = Counter(nums)
41      
42        # Check if any frequency value is a prime number
43        return any(is_prime(frequency) for frequency in frequency_map.values())
44
1import java.util.*;
2
3class Solution {
4    /**
5     * Checks if any element in the array appears a prime number of times.
6     * 
7     * @param nums the input array of integers
8     * @return true if at least one element appears a prime number of times, false otherwise
9     */
10    public boolean checkPrimeFrequency(int[] nums) {
11        // Create a frequency map to count occurrences of each element
12        Map<Integer, Integer> frequencyMap = new HashMap<>();
13      
14        // Count the frequency of each element in the array
15        for (int num : nums) {
16            frequencyMap.merge(num, 1, Integer::sum);
17        }
18      
19        // Check if any frequency value is a prime number
20        for (int frequency : frequencyMap.values()) {
21            if (isPrime(frequency)) {
22                return true;
23            }
24        }
25      
26        return false;
27    }
28  
29    /**
30     * Determines whether a given number is prime.
31     * 
32     * @param num the number to check for primality
33     * @return true if the number is prime, false otherwise
34     */
35    private boolean isPrime(int num) {
36        // Numbers less than 2 are not prime
37        if (num < 2) {
38            return false;
39        }
40      
41        // Check for divisibility from 2 up to sqrt(num)
42        // Using i * i <= num to avoid computing sqrt
43        for (int i = 2; i * i <= num; i++) {
44            if (num % i == 0) {
45                return false;
46            }
47        }
48      
49        return true;
50    }
51}
52
1class Solution {
2public:
3    /**
4     * Checks if any element in the array appears a prime number of times
5     * @param nums Input vector of integers
6     * @return true if at least one element has a prime frequency, false otherwise
7     */
8    bool checkPrimeFrequency(vector<int>& nums) {
9        // Create a frequency map to count occurrences of each element
10        unordered_map<int, int> frequencyMap;
11      
12        // Count the frequency of each element in the array
13        for (int num : nums) {
14            ++frequencyMap[num];
15        }
16
17        // Check if any frequency is a prime number
18        for (const auto& [element, frequency] : frequencyMap) {
19            if (isPrime(frequency)) {
20                return true;
21            }
22        }
23      
24        return false;
25    }
26
27private:
28    /**
29     * Determines if a given number is prime
30     * @param n The number to check for primality
31     * @return true if n is prime, false otherwise
32     */
33    bool isPrime(int n) {
34        // Numbers less than 2 are not prime
35        if (n < 2) {
36            return false;
37        }
38      
39        // Check for divisibility from 2 to sqrt(n)
40        // Using i * i <= n to avoid sqrt calculation
41        for (int i = 2; i * i <= n; ++i) {
42            if (n % i == 0) {
43                return false;  // Found a divisor, not prime
44            }
45        }
46      
47        return true;  // No divisors found, number is prime
48    }
49};
50
1/**
2 * Checks if any element in the array appears a prime number of times
3 * @param nums - The input array of numbers
4 * @returns true if at least one element appears a prime number of times, false otherwise
5 */
6function checkPrimeFrequency(nums: number[]): boolean {
7    // Create a frequency map to count occurrences of each element
8    const frequencyMap: Record<number, number> = {};
9  
10    // Count the frequency of each element in the array
11    for (const num of nums) {
12        frequencyMap[num] = (frequencyMap[num] || 0) + 1;
13    }
14  
15    // Check if any frequency is a prime number
16    for (const frequency of Object.values(frequencyMap)) {
17        if (isPrime(frequency)) {
18            return true;
19        }
20    }
21  
22    return false;
23}
24
25/**
26 * Determines if a given number is prime
27 * @param x - The number to check for primality
28 * @returns true if the number is prime, false otherwise
29 */
30function isPrime(x: number): boolean {
31    // Numbers less than 2 are not prime
32    if (x < 2) {
33        return false;
34    }
35  
36    // Check for divisors from 2 up to sqrt(x)
37    for (let i = 2; i * i <= x; i++) {
38        if (x % i === 0) {
39            return false;
40        }
41    }
42  
43    return true;
44}
45

Time and Space Complexity

The time complexity is O(n + k × √M), where n is the length of the array nums, k is the number of unique elements in nums, and M is the maximum frequency value in the counter.

  • Creating the Counter takes O(n) time as it iterates through all elements once
  • The any() function iterates through at most k unique frequency values
  • For each frequency value x, the is_prime() function checks primality in O(√x) time
  • In the worst case, the maximum frequency could be n (when all elements are the same), so M ≤ n
  • Therefore, the overall time complexity is O(n + k × √M), which simplifies to O(n × √M) in the worst case when k approaches n and considering that M can be at most n

The space complexity is O(n), where n is the length of the array nums.

  • The Counter object stores at most n key-value pairs (in the worst case when all elements are unique)
  • The is_prime() function uses O(1) additional space
  • Therefore, the overall space complexity is O(n)

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

Common Pitfalls

1. Inefficient Prime Checking for Large Frequencies

The Pitfall: The current implementation checks primality for every frequency value independently. If multiple elements have the same frequency, we're redundantly checking the same number for primality multiple times. Additionally, if frequencies are large, checking each one individually can be inefficient.

Example scenario:

nums = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]  # All elements appear 2 times
# We check if 2 is prime 5 times unnecessarily

Solution: Cache prime checking results or pre-check unique frequencies:

def checkPrimeFrequency(self, nums: List[int]) -> bool:
    frequency_map = Counter(nums)
  
    # Get unique frequencies only
    unique_frequencies = set(frequency_map.values())
  
    # Check each unique frequency once
    return any(is_prime(freq) for freq in unique_frequencies)

2. Edge Case: Empty Array

The Pitfall: The code doesn't explicitly handle empty arrays. While Counter([]) returns an empty Counter and any() on an empty iterable returns False, it's not immediately clear from reading the code.

Solution: Add an explicit check for clarity:

def checkPrimeFrequency(self, nums: List[int]) -> bool:
    if not nums:
        return False
  
    frequency_map = Counter(nums)
    return any(is_prime(frequency) for frequency in frequency_map.values())

3. Integer Overflow in Prime Checking

The Pitfall: For extremely large frequency values, the prime checking loop range(2, int(sqrt(n)) + 1) could potentially cause issues with very large ranges, though this is unlikely in practical scenarios.

Solution: Add an early termination for known non-prime patterns:

def is_prime(n: int) -> bool:
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:  # Even numbers > 2 are not prime
        return False
  
    # Only check odd divisors from 3 onwards
    for i in range(3, int(sqrt(n)) + 1, 2):
        if n % i == 0:
            return False
    return True

4. Using all() with Generator Expression in Prime Check

The Pitfall: The original code uses all(x % i for i in range(2, int(sqrt(x)) + 1)). This is clever but can be less readable and potentially confusing. When the range is empty (for x = 2), all() returns True by default, which works correctly but isn't intuitive.

Solution: Use a more explicit approach:

def is_prime(n: int) -> bool:
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
  
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

This optimized version checks 2 and 3 explicitly, then checks only numbers of the form 6k ± 1, which are the only possible forms for primes > 3.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What's the output of running the following function using the following tree as input?

1def serialize(root):
2    res = []
3    def dfs(root):
4        if not root:
5            res.append('x')
6            return
7        res.append(root.val)
8        dfs(root.left)
9        dfs(root.right)
10    dfs(root)
11    return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4    StringJoiner res = new StringJoiner(" ");
5    serializeDFS(root, res);
6    return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10    if (root == null) {
11        result.add("x");
12        return;
13    }
14    result.add(Integer.toString(root.val));
15    serializeDFS(root.left, result);
16    serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2    let res = [];
3    serialize_dfs(root, res);
4    return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8    if (!root) {
9        res.push("x");
10        return;
11    }
12    res.push(root.val);
13    serialize_dfs(root.left, res);
14    serialize_dfs(root.right, res);
15}
16

Recommended Readings

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

Load More