Facebook Pixel

3483. Unique 3-Digit Even Numbers

EasyRecursionArrayHash TableEnumeration
Leetcode Link

Problem Description

You are given an array of digits (0-9) and need to find how many distinct three-digit even numbers can be formed using these digits.

The key constraints are:

  • The number must be a valid three-digit number (100-999), so it cannot have leading zeros
  • The number must be even (last digit must be 0, 2, 4, 6, or 8)
  • Each digit from the array can be used at most once per number (if a digit appears multiple times in the array, each occurrence is treated as a separate digit that can be used)
  • You need to count only distinct numbers (no duplicates)

For example, if you have digits [1, 2, 3, 4], you could form numbers like:

  • 132 (even, ends with 2)
  • 124 (even, ends with 4)
  • 312 (even, ends with 2)
  • And so on...

The solution uses three nested loops to enumerate all possible combinations:

  1. The outer loop picks the last digit (must be even for the number to be even)
  2. The middle loop picks the middle digit (cannot be the same position as the last digit)
  3. The inner loop picks the first digit (cannot be 0 for a valid three-digit number, and cannot use positions already taken)

The number is constructed as c * 100 + b * 10 + a where c is the hundreds digit, b is the tens digit, and a is the units digit. A set is used to automatically handle duplicates, ensuring only distinct numbers are counted.

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

Intuition

To form a valid three-digit even number, we need to think about the constraints for each position:

  1. Units place (rightmost digit): Must be even (0, 2, 4, 6, or 8) for the entire number to be even
  2. Hundreds place (leftmost digit): Cannot be 0 (otherwise it wouldn't be a three-digit number)
  3. Tens place (middle digit): Can be any digit from 0-9

Since we need to count distinct numbers and each digit position in the array can only be used once, we face a selection problem. We're essentially picking 3 positions from the array to form our number, with specific constraints on what values those positions can have.

The natural approach is to enumerate all valid combinations. We start by fixing the units digit (checking if it's even), then try all possible tens digits (avoiding the position we already used), and finally try all possible hundreds digits (avoiding both previously used positions and the value 0).

Why use a hash set? As we generate numbers, the same three-digit number might be formed from different combinations of array positions. For instance, if the array is [1, 2, 1, 2], we could form 212 using positions (0, 1, 3) or positions (2, 1, 3). The set automatically handles this deduplication for us.

The key insight is that we're not just looking at the values in the array, but at the positions of those values. This is why the solution uses indices i, j, k to ensure we don't reuse the same position, even if the same digit value appears multiple times in the array.

Learn more about Recursion patterns.

Solution Approach

The solution uses a hash set with enumeration approach to find all distinct three-digit even numbers.

Data Structure Used:

  • A hash set s to store distinct three-digit numbers and automatically handle duplicates

Algorithm Steps:

  1. Initialize an empty set s to store distinct numbers.

  2. First loop - Fix the units digit: Iterate through each digit at position i in the array:

    • Check if the digit a is even using bitwise AND: if a & 1 (if the result is 1, the number is odd, so we skip it)
    • If odd, continue to the next iteration
    • If even, this digit can be our units place
  3. Second loop - Fix the tens digit: For each valid units digit, iterate through all positions j:

    • Skip if i == j (can't reuse the same position)
    • The digit b at position j becomes our tens digit
  4. Third loop - Fix the hundreds digit: For each valid units and tens combination, iterate through all positions k:

    • Check two conditions:
      • c == 0: Skip if the digit is 0 (no leading zeros allowed)
      • k in (i, j): Skip if position k is already used
    • If valid, the digit c at position k becomes our hundreds digit
  5. Form the number and add to set:

    • Calculate the three-digit number as c * 100 + b * 10 + a
    • Add it to the set (duplicates are automatically ignored)
  6. Return the count: Return len(s), which gives us the total number of distinct three-digit even numbers.

Time Complexity: O(nΒ³) where n is the length of the digits array, as we have three nested loops.

Space Complexity: O(m) where m is the number of distinct three-digit even numbers that can be formed (at most 450 for even numbers from 100-998).

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

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

Step 1: Initialize empty set

  • s = {}

Step 2: Iterate through positions for units digit (must be even)

When i = 0 (digit = 2, even βœ“):

  • j = 1 (digit = 1):
    • k = 2 (digit = 3): Form 312 β†’ Add to set
    • k = 3 (digit = 0): Skip (0 cannot be hundreds digit)
  • j = 2 (digit = 3):
    • k = 1 (digit = 1): Form 132 β†’ Add to set
    • k = 3 (digit = 0): Skip (0 cannot be hundreds digit)
  • j = 3 (digit = 0):
    • k = 1 (digit = 1): Form 102 β†’ Add to set
    • k = 2 (digit = 3): Form 302 β†’ Add to set

When i = 1 (digit = 1, odd):

  • Skip (not even)

When i = 2 (digit = 3, odd):

  • Skip (not even)

When i = 3 (digit = 0, even βœ“):

  • j = 0 (digit = 2):
    • k = 1 (digit = 1): Form 120 β†’ Add to set
    • k = 2 (digit = 3): Form 320 β†’ Add to set
  • j = 1 (digit = 1):
    • k = 0 (digit = 2): Form 210 β†’ Add to set
    • k = 2 (digit = 3): Form 310 β†’ Add to set
  • j = 2 (digit = 3):
    • k = 0 (digit = 2): Form 230 β†’ Add to set
    • k = 1 (digit = 1): Form 130 β†’ Add to set

Step 3: Count distinct numbers

  • Final set: {312, 132, 102, 302, 120, 320, 210, 310, 230, 130}
  • Return len(s) = 10

The algorithm successfully finds all 10 distinct three-digit even numbers that can be formed from the digits [2, 1, 3, 0].

Solution Implementation

1class Solution:
2    def totalNumbers(self, digits: List[int]) -> int:
3        # Set to store unique 3-digit numbers
4        unique_numbers = set()
5      
6        # Iterate through all digits to find candidates for ones place (must be even)
7        for ones_index, ones_digit in enumerate(digits):
8            # Skip if ones digit is odd (number must be even)
9            if ones_digit & 1:
10                continue
11          
12            # Iterate through all digits for tens place
13            for tens_index, tens_digit in enumerate(digits):
14                # Skip if using the same digit position as ones place
15                if ones_index == tens_index:
16                    continue
17              
18                # Iterate through all digits for hundreds place
19                for hundreds_index, hundreds_digit in enumerate(digits):
20                    # Skip if hundreds digit is 0 (not valid for 3-digit number)
21                    # or if using same digit position as ones or tens place
22                    if hundreds_digit == 0 or hundreds_index in (ones_index, tens_index):
23                        continue
24                  
25                    # Construct the 3-digit number and add to set
26                    number = hundreds_digit * 100 + tens_digit * 10 + ones_digit
27                    unique_numbers.add(number)
28      
29        # Return count of unique 3-digit numbers
30        return len(unique_numbers)
31
1class Solution {
2    public int totalNumbers(int[] digits) {
3        // Use a HashSet to store unique 3-digit numbers
4        Set<Integer> uniqueNumbers = new HashSet<>();
5        int arrayLength = digits.length;
6      
7        // Iterate through all possible positions for the ones digit (must be even)
8        for (int onesIndex = 0; onesIndex < arrayLength; ++onesIndex) {
9            // Skip if the digit at this position is odd
10            if (digits[onesIndex] % 2 == 1) {
11                continue;
12            }
13          
14            // Iterate through all possible positions for the tens digit
15            for (int tensIndex = 0; tensIndex < arrayLength; ++tensIndex) {
16                // Skip if using the same index as the ones digit
17                if (onesIndex == tensIndex) {
18                    continue;
19                }
20              
21                // Iterate through all possible positions for the hundreds digit
22                for (int hundredsIndex = 0; hundredsIndex < arrayLength; ++hundredsIndex) {
23                    // Skip if:
24                    // 1. The digit is 0 (cannot be in hundreds place)
25                    // 2. The index is already used for ones or tens digit
26                    if (digits[hundredsIndex] == 0 || 
27                        hundredsIndex == onesIndex || 
28                        hundredsIndex == tensIndex) {
29                        continue;
30                    }
31                  
32                    // Form the 3-digit number and add to set
33                    int threeDigitNumber = digits[hundredsIndex] * 100 + 
34                                         digits[tensIndex] * 10 + 
35                                         digits[onesIndex];
36                    uniqueNumbers.add(threeDigitNumber);
37                }
38            }
39        }
40      
41        // Return the count of unique 3-digit numbers formed
42        return uniqueNumbers.size();
43    }
44}
45
1class Solution {
2public:
3    int totalNumbers(vector<int>& digits) {
4        // Use unordered_set to store unique 3-digit numbers
5        unordered_set<int> uniqueNumbers;
6        int n = digits.size();
7      
8        // Iterate through all possible positions for the ones place (last digit)
9        for (int i = 0; i < n; ++i) {
10            // Skip if the digit at position i is odd (ones place must be even)
11            if (digits[i] % 2 == 1) {
12                continue;
13            }
14          
15            // Iterate through all possible positions for the tens place (middle digit)
16            for (int j = 0; j < n; ++j) {
17                // Skip if trying to use the same digit position as ones place
18                if (i == j) {
19                    continue;
20                }
21              
22                // Iterate through all possible positions for the hundreds place (first digit)
23                for (int k = 0; k < n; ++k) {
24                    // Skip if:
25                    // 1. The digit is 0 (cannot be the first digit of a 3-digit number)
26                    // 2. Position k is already used for ones or tens place
27                    if (digits[k] == 0 || k == i || k == j) {
28                        continue;
29                    }
30                  
31                    // Construct the 3-digit number and add to set
32                    // hundreds place * 100 + tens place * 10 + ones place
33                    int number = digits[k] * 100 + digits[j] * 10 + digits[i];
34                    uniqueNumbers.insert(number);
35                }
36            }
37        }
38      
39        // Return the count of unique valid 3-digit even numbers
40        return uniqueNumbers.size();
41    }
42};
43
1/**
2 * Counts unique three-digit numbers where:
3 * - The last digit (ones place) is even
4 * - The first digit (hundreds place) is non-zero
5 * - All three digits come from different positions in the input array
6 * 
7 * @param digits - Array of single digits (0-9)
8 * @returns The count of unique valid three-digit numbers
9 */
10function totalNumbers(digits: number[]): number {
11    // Set to store unique three-digit numbers
12    const uniqueNumbers = new Set<number>();
13    const arrayLength = digits.length;
14  
15    // Iterate through all positions for the ones place (last digit)
16    for (let onesIndex = 0; onesIndex < arrayLength; ++onesIndex) {
17        // Skip if the ones digit is odd (must be even)
18        if (digits[onesIndex] % 2 === 1) {
19            continue;
20        }
21      
22        // Iterate through all positions for the tens place (middle digit)
23        for (let tensIndex = 0; tensIndex < arrayLength; ++tensIndex) {
24            // Skip if using the same position as ones digit
25            if (onesIndex === tensIndex) {
26                continue;
27            }
28          
29            // Iterate through all positions for the hundreds place (first digit)
30            for (let hundredsIndex = 0; hundredsIndex < arrayLength; ++hundredsIndex) {
31                // Skip if:
32                // - The hundreds digit is 0 (invalid for first digit)
33                // - Using the same position as ones or tens digit
34                if (digits[hundredsIndex] === 0 || 
35                    hundredsIndex === onesIndex || 
36                    hundredsIndex === tensIndex) {
37                    continue;
38                }
39              
40                // Construct the three-digit number and add to set
41                const threeDigitNumber = digits[hundredsIndex] * 100 + 
42                                        digits[tensIndex] * 10 + 
43                                        digits[onesIndex];
44                uniqueNumbers.add(threeDigitNumber);
45            }
46        }
47    }
48  
49    // Return the count of unique numbers
50    return uniqueNumbers.size;
51}
52

Time and Space Complexity

The time complexity is O(nΒ³), where n is the length of the array digits.

This is because the code contains three nested loops:

  • The outer loop iterates through all digits (n iterations)
  • The middle loop iterates through all digits (n iterations)
  • The inner loop iterates through all digits (n iterations)

Even though there are early continue statements that skip some iterations (when a is odd, when i == j, or when c == 0 or k is in (i, j)), these conditions only affect constant factors. In the worst case, we still need to examine all possible combinations of three positions from the array, resulting in O(nΒ³) time complexity.

The space complexity is O(nΒ³), where n is the length of the array digits.

The set s stores unique three-digit numbers formed by the digits. In the worst case, if all digits are distinct and meet the conditions (even last digit, non-zero first digit), we could potentially store up to O(nΒ³) unique three-digit numbers in the set. Each unique combination of three positions with valid digits creates a distinct number that gets added to the set.

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

Common Pitfalls

1. Confusing digit value with array index

A frequent mistake is treating the digit positions and digit values interchangeably. The code correctly uses indices to track which positions in the array have been used, but developers often mistakenly compare digit values instead of indices.

Incorrect approach:

# Wrong: comparing digit values instead of indices
if hundreds_digit == ones_digit or hundreds_digit == tens_digit:
    continue

Correct approach:

# Right: comparing indices to ensure each position is used only once
if hundreds_index in (ones_index, tens_index):
    continue

2. Incorrectly checking for even numbers

Some developers check evenness of the wrong digit or place the check in the wrong position.

Incorrect approach:

# Wrong: checking evenness after forming the number
number = hundreds_digit * 100 + tens_digit * 10 + ones_digit
if number % 2 == 0:
    unique_numbers.add(number)

Correct approach:

# Right: check ones digit for evenness before proceeding
if ones_digit & 1:  # Skip odd digits
    continue

3. Allowing duplicate digits when the array has duplicates

If the input array is [2, 2, 8, 8, 2], each occurrence is a separate digit that can be used. However, a common mistake is to deduplicate the input array first, which would incorrectly reduce the number of possible combinations.

Incorrect approach:

# Wrong: removing duplicates from input
digits = list(set(digits))  # This loses valid digit occurrences

Correct approach:

# Right: treat each array element as a separate digit
for ones_index, ones_digit in enumerate(digits):
    # Each index represents a unique position, even if values are the same

4. Using the wrong data structure for storing results

Using a list instead of a set would require manual duplicate checking, making the code more complex and error-prone.

Incorrect approach:

# Wrong: using list and manual duplicate checking
result = []
number = hundreds_digit * 100 + tens_digit * 10 + ones_digit
if number not in result:  # O(n) check each time
    result.append(number)

Correct approach:

# Right: using set for automatic duplicate handling
unique_numbers = set()
unique_numbers.add(number)  # O(1) operation with automatic deduplication
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What does the following code do?

1def f(arr1, arr2):
2  i, j = 0, 0
3  new_arr = []
4  while i < len(arr1) and j < len(arr2):
5      if arr1[i] < arr2[j]:
6          new_arr.append(arr1[i])
7          i += 1
8      else:
9          new_arr.append(arr2[j])
10          j += 1
11  new_arr.extend(arr1[i:])
12  new_arr.extend(arr2[j:])
13  return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2  int i = 0, j = 0;
3  List<Integer> newArr = new ArrayList<>();
4
5  while (i < arr1.length && j < arr2.length) {
6      if (arr1[i] < arr2[j]) {
7          newArr.add(arr1[i]);
8          i++;
9      } else {
10          newArr.add(arr2[j]);
11          j++;
12      }
13  }
14
15  while (i < arr1.length) {
16      newArr.add(arr1[i]);
17      i++;
18  }
19
20  while (j < arr2.length) {
21      newArr.add(arr2[j]);
22      j++;
23  }
24
25  return newArr;
26}
27
1function f(arr1, arr2) {
2  let i = 0, j = 0;
3  let newArr = [];
4  
5  while (i < arr1.length && j < arr2.length) {
6      if (arr1[i] < arr2[j]) {
7          newArr.push(arr1[i]);
8          i++;
9      } else {
10          newArr.push(arr2[j]);
11          j++;
12      }
13  }
14  
15  while (i < arr1.length) {
16      newArr.push(arr1[i]);
17      i++;
18  }
19  
20  while (j < arr2.length) {
21      newArr.push(arr2[j]);
22      j++;
23  }
24  
25  return newArr;
26}
27

Recommended Readings

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

Load More