3591. Check if Any Element Has Prime Frequency
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:
- Count how many times each element appears in the array (this is called the frequency)
- Check if any of these frequencies is a prime number
- Return
true
if at least one element has a prime frequency, otherwise returnfalse
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
.
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 tosqrt(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 tosqrt(x)
- The
all()
function returnsTrue
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 EvaluatorExample 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 mostk
unique frequency values - For each frequency value
x
, theis_prime()
function checks primality inO(√x)
time - In the worst case, the maximum frequency could be
n
(when all elements are the same), soM ≤ n
- Therefore, the overall time complexity is
O(n + k × √M)
, which simplifies toO(n × √M)
in the worst case whenk
approachesn
and considering thatM
can be at mostn
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 usesO(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.
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
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!