Facebook Pixel

2094. Finding 3-Digit Even Numbers

EasyArrayHash TableEnumerationSorting
Leetcode Link

Problem Description

You are given an integer array digits where each element is a single digit (0-9). The array may contain duplicate values.

Your task is to find all unique integers that satisfy these three conditions:

  1. The integer is formed by concatenating exactly three elements from the digits array. You can pick any three elements in any order (the same element can be used multiple times if it appears multiple times in the array).

  2. The integer cannot have leading zeros. This means the integer must be between 100 and 999 (inclusive).

  3. The integer must be even. This means it must end with 0, 2, 4, 6, or 8.

For example, if digits = [1, 2, 3]:

  • You can form 132 by using digits 1, 3, and 2
  • You can form 312 by using digits 3, 1, and 2
  • Both are valid because they are 3-digit numbers without leading zeros and are even

The output should be a sorted array containing all unique integers that meet these requirements.

Key Points:

  • Each digit in the array can only be used as many times as it appears in the original array
  • If digits = [1, 2, 2], you can form 122 or 212, but not 222 (since there's only two 2's)
  • The result should contain no duplicates and be sorted in ascending order
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we need to find all valid 3-digit even numbers that can be formed from the given digits, a natural first thought might be to generate all possible combinations of three digits. However, this would involve checking permutations and dealing with duplicates, which can get complicated.

Instead, let's think about this problem from a different angle. We know that:

  • Valid numbers are between 100 and 999
  • They must be even (end with 0, 2, 4, 6, or 8)
  • They can only use digits available in our array

This suggests a simpler approach: why not just check every even number from 100 to 998?

For each even number in this range, we can break it down into its individual digits and check if we have enough of each digit in our original array. This is like asking: "Can I build this number using the digits I have available?"

Think of it like having a bag of digit tiles. For each even number from 100 to 998:

  • Break the number into its three digits (e.g., 234 β†’ 2, 3, 4)
  • Check if we have enough of each required digit in our bag
  • If yes, this number is valid

To efficiently check if we have enough digits, we can:

  1. Count how many times each digit appears in our original array (store in cnt)
  2. For each candidate number, count what digits it needs (store in cnt1)
  3. Compare: do we have at least as many of each digit as needed?

This approach is elegant because it avoids the complexity of generating combinations and automatically handles uniqueness - we're checking each possible number exactly once.

Learn more about Sorting patterns.

Solution Approach

Following our intuition, we implement the solution using a counting and enumeration strategy:

Step 1: Count Available Digits

cnt = Counter(digits)

We use Python's Counter to count how many times each digit (0-9) appears in the input array. This gives us our "inventory" of available digits.

Step 2: Initialize Result Array

ans = []

This will store all valid even numbers we find.

Step 3: Enumerate Even Numbers

for x in range(100, 1000, 2):

We iterate through all even numbers from 100 to 998. The step size of 2 ensures we only check even numbers (100, 102, 104, ..., 998).

Step 4: Extract and Count Digits of Current Number

cnt1 = Counter()
y = x
while y:
    y, v = divmod(y, 10)
    cnt1[v] += 1

For each candidate number x:

  • Create a new counter cnt1 to track what digits this number needs
  • Use divmod(y, 10) to extract digits one by one:
    • v gets the last digit (remainder when divided by 10)
    • y becomes the number with the last digit removed (quotient)
    • Add each extracted digit to cnt1

For example, if x = 234:

  • First iteration: y = 23, v = 4, so cnt1[4] = 1
  • Second iteration: y = 2, v = 3, so cnt1[3] = 1
  • Third iteration: y = 0, v = 2, so cnt1[2] = 1

Step 5: Check Availability

if all(cnt[i] >= cnt1[i] for i in range(10)):
    ans.append(x)

We check if we have enough of each digit (0-9) to form the current number:

  • For each digit i from 0 to 9, verify that cnt[i] >= cnt1[i]
  • This means we have at least as many of digit i as needed
  • If all digits pass this check, the number is valid and we add it to our answer

Step 6: Return Result

return ans

The answer array is already sorted because we enumerated numbers in ascending order.

Time Complexity: O(1) - We check at most 450 even numbers (from 100 to 998), and for each number, we perform constant-time operations.

Space Complexity: O(1) - The counters store at most 10 digits, which is constant space.

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 digits = [2, 2, 8, 8, 2].

Step 1: Count Available Digits

cnt = {2: 3, 8: 2}  # We have three 2's and two 8's

Step 2: Check Even Numbers from 100-998

Let's trace through a few numbers:

Checking x = 222:

  • Extract digits: 222 β†’ needs {2: 3}
  • Compare with available: We have {2: 3}, need {2: 3}
  • βœ“ Valid! Add 222 to result

Checking x = 224:

  • Extract digits: 224 β†’ needs {2: 2, 4: 1}
  • Compare with available: We have {2: 3} but no 4's
  • βœ— Invalid (missing digit 4)

Checking x = 228:

  • Extract digits: 228 β†’ needs {2: 2, 8: 1}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 228 to result

Checking x = 282:

  • Extract digits: 282 β†’ needs {2: 2, 8: 1}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 282 to result

Checking x = 288:

  • Extract digits: 288 β†’ needs {2: 1, 8: 2}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 288 to result

Checking x = 822:

  • Extract digits: 822 β†’ needs {8: 1, 2: 2}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 822 to result

Checking x = 828:

  • Extract digits: 828 β†’ needs {8: 2, 2: 1}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 828 to result

Checking x = 882:

  • Extract digits: 882 β†’ needs {8: 2, 2: 1}
  • Compare with available: We have {2: 3, 8: 2}
  • βœ“ Valid! Add 882 to result

Checking x = 888:

  • Extract digits: 888 β†’ needs {8: 3}
  • Compare with available: We have {8: 2} but need {8: 3}
  • βœ— Invalid (not enough 8's)

Final Result: [222, 228, 282, 288, 822, 828, 882]

The result is automatically sorted since we checked numbers in ascending order.

Solution Implementation

1class Solution:
2    def findEvenNumbers(self, digits: List[int]) -> List[int]:
3        """
4        Find all unique 3-digit even numbers that can be formed using the given digits.
5      
6        Args:
7            digits: List of single digits (0-9)
8      
9        Returns:
10            List of 3-digit even numbers in ascending order
11        """
12        # Count frequency of each digit in the input array
13        digit_frequency = Counter(digits)
14        result = []
15      
16        # Iterate through all 3-digit even numbers (100 to 998)
17        for number in range(100, 1000, 2):
18            # Count frequency of digits in the current number
19            number_digit_frequency = Counter()
20            temp_number = number
21          
22            # Extract each digit from the number and count its frequency
23            while temp_number > 0:
24                temp_number, remainder = divmod(temp_number, 10)
25                number_digit_frequency[remainder] += 1
26          
27            # Check if we have enough digits to form this number
28            # For each digit (0-9), verify that available count >= required count
29            can_form_number = all(
30                digit_frequency[digit] >= number_digit_frequency[digit] 
31                for digit in range(10)
32            )
33          
34            if can_form_number:
35                result.append(number)
36      
37        return result
38
1class Solution {
2    public int[] findEvenNumbers(int[] digits) {
3        // Count frequency of each digit in the input array
4        int[] digitFrequency = new int[10];
5        for (int digit : digits) {
6            digitFrequency[digit]++;
7        }
8      
9        // List to store valid three-digit even numbers
10        List<Integer> validNumbers = new ArrayList<>();
11      
12        // Iterate through all three-digit even numbers (100 to 998)
13        for (int number = 100; number < 1000; number += 2) {
14            // Count frequency of digits in the current number
15            int[] numberDigitFrequency = new int[10];
16            int temp = number;
17            while (temp > 0) {
18                numberDigitFrequency[temp % 10]++;
19                temp /= 10;
20            }
21          
22            // Check if the current number can be formed from available digits
23            boolean canFormNumber = true;
24            for (int i = 0; i < 10; i++) {
25                // If the number requires more of a digit than available, it cannot be formed
26                if (digitFrequency[i] < numberDigitFrequency[i]) {
27                    canFormNumber = false;
28                    break;
29                }
30            }
31          
32            // Add the number to result if it can be formed
33            if (canFormNumber) {
34                validNumbers.add(number);
35            }
36        }
37      
38        // Convert list to array and return
39        return validNumbers.stream().mapToInt(Integer::intValue).toArray();
40    }
41}
42
1class Solution {
2public:
3    vector<int> findEvenNumbers(vector<int>& digits) {
4        // Count frequency of each digit in the input array
5        int digitFrequency[10]{};
6        for (int digit : digits) {
7            ++digitFrequency[digit];
8        }
9      
10        vector<int> result;
11      
12        // Iterate through all even three-digit numbers (100 to 998)
13        for (int number = 100; number < 1000; number += 2) {
14            // Count frequency of each digit in the current number
15            int numberDigitFrequency[10]{};
16            int temp = number;
17            while (temp > 0) {
18                ++numberDigitFrequency[temp % 10];
19                temp /= 10;
20            }
21          
22            // Check if the current number can be formed using available digits
23            bool canFormNumber = true;
24            for (int i = 0; i < 10; ++i) {
25                if (digitFrequency[i] < numberDigitFrequency[i]) {
26                    canFormNumber = false;
27                    break;
28                }
29            }
30          
31            // Add the number to result if it can be formed
32            if (canFormNumber) {
33                result.push_back(number);
34            }
35        }
36      
37        return result;
38    }
39};
40
1/**
2 * Finds all possible 3-digit even numbers that can be formed using the given digits
3 * @param digits - Array of single digits (0-9) that can be used to form numbers
4 * @returns Array of unique 3-digit even numbers in ascending order
5 */
6function findEvenNumbers(digits: number[]): number[] {
7    // Count the frequency of each digit (0-9) in the input array
8    const digitFrequency: number[] = Array(10).fill(0);
9    for (const digit of digits) {
10        digitFrequency[digit]++;
11    }
12  
13    const result: number[] = [];
14  
15    // Iterate through all 3-digit even numbers (100 to 998)
16    for (let number = 100; number < 1000; number += 2) {
17        // Count the frequency of each digit in the current number
18        const numberDigitFrequency: number[] = Array(10).fill(0);
19        let tempNumber = number;
20      
21        // Extract each digit from the number and count its frequency
22        while (tempNumber > 0) {
23            const digit = tempNumber % 10;
24            numberDigitFrequency[digit]++;
25            tempNumber = Math.floor(tempNumber / 10);
26        }
27      
28        // Check if the current number can be formed using available digits
29        let canFormNumber = true;
30        for (let i = 0; i < 10; i++) {
31            // If any digit appears more in the number than available, cannot form
32            if (digitFrequency[i] < numberDigitFrequency[i]) {
33                canFormNumber = false;
34                break;
35            }
36        }
37      
38        // Add the number to result if it can be formed
39        if (canFormNumber) {
40            result.push(number);
41        }
42    }
43  
44    return result;
45}
46

Time and Space Complexity

Time Complexity: O(k Γ— 10^k) where k = 3 is the number of digits in the target even numbers.

The algorithm iterates through all even numbers from 100 to 998 (inclusive), which gives us 450 iterations. For each number x, it extracts digits using a while loop that runs k times (3 times for 3-digit numbers). Inside the loop, there's a divmod operation which is O(1). After extracting digits, it checks if all 10 possible digits (0-9) satisfy the condition cnt[i] >= cnt1[i], which takes O(10) = O(1) time.

Therefore, the total time complexity is O(450 Γ— 3) = O(1350) = O(k Γ— 10^k) where 10^k represents the range of k-digit numbers and the constant factor accounts for checking only even numbers and the digit extraction process.

Space Complexity: O(1) (excluding the space for the answer array)

The algorithm uses:

  • cnt: A Counter object storing at most 10 key-value pairs (digits 0-9), which is O(1)
  • cnt1: Another Counter object also storing at most 10 key-value pairs, which is O(1)
  • A few integer variables (x, y, v), each taking O(1) space

The answer array ans can contain at most O(10^k) elements, but as stated in the reference, we exclude this from the space complexity analysis. Thus, the space complexity is O(1).

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

Common Pitfalls

Pitfall 1: Misunderstanding Digit Usage Constraints

The Problem: A common mistake is thinking that each position in the array can only be used once, rather than understanding that each digit VALUE can be used up to the number of times it appears.

Incorrect Approach:

# WRONG: Trying to use array indices/positions
def findEvenNumbers(self, digits: List[int]) -> List[int]:
    result = []
    n = len(digits)
    # This generates combinations of indices, not digit values
    for i in range(n):
        for j in range(n):
            for k in range(n):
                if i != j and j != k and i != k:  # Wrong constraint!
                    num = digits[i] * 100 + digits[j] * 10 + digits[k]
                    if num >= 100 and num % 2 == 0:
                        result.append(num)
    return sorted(list(set(result)))

Why It's Wrong: If digits = [1, 2, 2], this approach wouldn't allow forming 221 because it requires using the digit 2 twice, but the index-based approach prevents reusing any position.

Correct Understanding: Count the frequency of each digit value. If you have two 2's in the array, you can use the digit 2 up to twice when forming a number.

Pitfall 2: Inefficient Permutation Generation

The Problem: Generating all possible 3-digit permutations first, then filtering for validity leads to duplicate work and complexity.

Inefficient Approach:

# INEFFICIENT: Generate all permutations first
def findEvenNumbers(self, digits: List[int]) -> List[int]:
    from itertools import permutations
    result = set()
  
    # This generates many duplicate combinations
    for perm in permutations(digits, 3):
        num = perm[0] * 100 + perm[1] * 10 + perm[2]
        if num >= 100 and num % 2 == 0:
            result.add(num)
  
    return sorted(list(result))

Why It's Inefficient:

  • For digits = [1, 1, 2, 2, 3, 3], this generates 6Γ—5Γ—4 = 120 permutations
  • Many permutations form the same number (e.g., using the first 1 vs the second 1)
  • We check many odd numbers and numbers with leading zeros unnecessarily

Better Solution: The provided approach iterates through only the 450 possible even 3-digit numbers and checks if each can be formed.

Pitfall 3: Forgetting Edge Cases with Zeros

The Problem: Not properly handling zeros, especially when they appear multiple times.

Problematic Scenario:

# Example that might cause issues:
digits = [0, 0, 2]
# Can form: 200 (valid)
# Cannot form: 002 (has leading zero, not a valid 3-digit number)

Key Points to Remember:

  • A 3-digit number cannot start with 0 (must be 100-999)
  • Zero can appear in the middle or end position
  • If you need multiple zeros (like in 200), ensure you have enough zeros in the input

The solution correctly handles this by only checking numbers in range(100, 1000, 2), automatically excluding numbers with leading zeros.

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

How would you design a stack which has a function min that returns the minimum element in the stack, in addition to push and pop? All push, pop, min should have running time O(1).


Recommended Readings

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

Load More