Facebook Pixel

3289. The Two Sneaky Numbers of Digitville

Problem Description

In the town of Digitville, there is a list of numbers called nums that should contain integers from 0 to n - 1. Each number is supposed to appear exactly once in the list. However, two mischievous numbers have sneaked in an additional time, making the list longer than it should be.

Your task is to find these two sneaky numbers that appear twice in the list. You need to return an array of size two containing these two duplicate numbers in any order.

For example, if the list should have contained [0, 1, 2, 3, 4] but instead contains [0, 1, 1, 2, 3, 3, 4], then the sneaky numbers are 1 and 3 since they each appear twice.

The solution uses a Counter to count the occurrences of each number in the list. It then filters out and returns only those numbers that appear exactly twice (count equals 2). This directly identifies the two sneaky numbers that violated the rule of appearing only once.

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

Intuition

Since we know that the list should contain each number from 0 to n - 1 exactly once, but two numbers appear twice, the most straightforward approach is to count how many times each number appears.

Think of it like taking attendance in a classroom - if we call out each student's name and mark them present, we'll quickly discover which two students showed up twice.

We can count occurrences by going through the list and keeping track of how many times we've seen each number. Once we have these counts, we simply need to identify which numbers have a count of 2 - these are our sneaky numbers.

The beauty of this approach is its simplicity. We don't need to sort the array or use complex mathematical formulas. We just count and filter. Python's Counter class makes this especially elegant - it automatically creates a dictionary-like object that counts occurrences for us. Then we can iterate through the counts and pick out any number that appears exactly twice.

This counting approach works because we have a clear pattern to look for: normal numbers appear once, sneaky numbers appear twice. By counting, we directly identify what breaks the pattern.

Learn more about Math patterns.

Solution Approach

The solution uses a counting approach to identify the two numbers that appear twice in the array.

We use an array or dictionary cnt to record the number of occurrences of each number in the input array nums. In the Python implementation, we use Counter from the collections module, which automatically creates a frequency map for us.

Here's how the algorithm works step by step:

  1. Count occurrences: We create a Counter object from the nums array. This gives us a dictionary-like structure where:

    • Keys are the numbers from the array
    • Values are the count of how many times each number appears
  2. Filter duplicates: We iterate through the items in our counter using cnt.items(), which gives us (number, count) pairs. For each pair, we check if the count v equals 2.

  3. Build result: We use a list comprehension [x for x, v in cnt.items() if v == 2] to collect all numbers x where the count v is exactly 2. Since we know there are exactly two sneaky numbers, this will return an array of size 2.

The time complexity is O(n) where n is the length of the input array, as we need to traverse the array once to count occurrences and then iterate through the unique numbers to find duplicates.

The space complexity is also O(n) in the worst case for storing the counter, though in practice it will be closer to O(n-2) since most numbers appear once.

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 a small example to see how the solution works.

Example Input: nums = [0, 3, 2, 1, 3, 2]

In this case, the array should have contained [0, 1, 2, 3] (numbers from 0 to n-1 where n=4), but numbers 2 and 3 appear twice.

Step 1: Count occurrences

We create a Counter from the array:

  • 0 appears 1 time
  • 1 appears 1 time
  • 2 appears 2 times
  • 3 appears 2 times

Our counter looks like: {0: 1, 3: 2, 2: 2, 1: 1}

Step 2: Filter for duplicates

We iterate through each (number, count) pair:

  • (0, 1): count is 1, not 2, so skip
  • (3, 2): count is 2, so add 3 to result
  • (2, 2): count is 2, so add 2 to result
  • (1, 1): count is 1, not 2, so skip

Step 3: Return result

Our list comprehension [x for x, v in cnt.items() if v == 2] produces [3, 2]

The sneaky numbers are 3 and 2, which is correct! The order doesn't matter, so [3, 2] or [2, 3] are both valid answers.

This approach efficiently identifies exactly which numbers violated the "appear once" rule by appearing twice instead.

Solution Implementation

1from typing import List
2from collections import Counter
3
4class Solution:
5    def getSneakyNumbers(self, nums: List[int]) -> List[int]:
6        # Count the frequency of each number in the array
7        frequency_map = Counter(nums)
8      
9        # Filter and return numbers that appear exactly twice
10        duplicates = [number for number, count in frequency_map.items() if count == 2]
11      
12        return duplicates
13
1class Solution {
2    /**
3     * Finds two numbers that appear twice in the array.
4     * All other numbers appear exactly once.
5     * 
6     * @param nums Input array containing numbers from 0 to n-1, where exactly 2 numbers appear twice
7     * @return Array containing the two numbers that appear twice
8     */
9    public int[] getSneakyNumbers(int[] nums) {
10        // Array to store the result (two duplicate numbers)
11        int[] result = new int[2];
12      
13        // Frequency counter array (assuming numbers range from 0 to 99)
14        int[] frequencyCounter = new int[100];
15      
16        // Index to track position in result array
17        int resultIndex = 0;
18      
19        // Iterate through each number in the input array
20        for (int currentNumber : nums) {
21            // Increment the frequency count for current number
22            frequencyCounter[currentNumber]++;
23          
24            // If this number appears for the second time, add it to result
25            if (frequencyCounter[currentNumber] == 2) {
26                result[resultIndex] = currentNumber;
27                resultIndex++;
28            }
29        }
30      
31        return result;
32    }
33}
34
1class Solution {
2public:
3    vector<int> getSneakyNumbers(vector<int>& nums) {
4        // Result vector to store numbers that appear exactly twice
5        vector<int> result;
6      
7        // Frequency array to count occurrences of each number (0-99)
8        int frequency[100] = {0};
9      
10        // Iterate through all numbers in the input array
11        for (int number : nums) {
12            // Increment the count for current number
13            frequency[number]++;
14          
15            // If this number appears exactly twice, add it to result
16            if (frequency[number] == 2) {
17                result.push_back(number);
18            }
19        }
20      
21        return result;
22    }
23};
24
1/**
2 * Finds duplicate numbers in an array where numbers appear more than once.
3 * @param nums - The input array of numbers to check for duplicates
4 * @returns An array containing numbers that appear more than once
5 */
6function getSneakyNumbers(nums: number[]): number[] {
7    // Array to store the duplicate numbers found
8    const duplicates: number[] = [];
9  
10    // Frequency counter array initialized with zeros (size 100 for numbers 0-99)
11    const frequencyCounter: number[] = Array(100).fill(0);
12  
13    // Iterate through each number in the input array
14    for (const currentNumber of nums) {
15        // Increment the frequency count for the current number
16        // If the count becomes greater than 1, it's a duplicate
17        if (++frequencyCounter[currentNumber] > 1) {
18            duplicates.push(currentNumber);
19        }
20    }
21  
22    return duplicates;
23}
24

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. This is because:

  • Creating a Counter object requires iterating through all n elements of the array once, which takes O(n) time
  • The list comprehension iterates through the items in the counter, which in the worst case contains n unique elements, taking O(n) time
  • Overall: O(n) + O(n) = O(n)

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

  • The Counter object stores at most n key-value pairs (in the worst case where all elements are unique), requiring O(n) space
  • The resulting list stores at most n elements (though typically much fewer), which is O(n) in the worst case
  • Overall: O(n) space is required

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

Common Pitfalls

1. Assuming Only Two Duplicates Exist

A common pitfall is assuming the problem guarantees exactly two numbers appear twice without validating the input. If the input is malformed (e.g., a number appears three times or more than two numbers are duplicated), the current solution might return incorrect results.

Solution: Add input validation to ensure the result contains exactly two elements:

def getSneakyNumbers(self, nums: List[int]) -> List[int]:
    frequency_map = Counter(nums)
    duplicates = [number for number, count in frequency_map.items() if count == 2]
  
    # Validate that we found exactly two duplicates
    if len(duplicates) != 2:
        raise ValueError(f"Expected exactly 2 duplicates, found {len(duplicates)}")
  
    return duplicates

2. Memory Overhead for Large Ranges

When dealing with very large arrays where n is substantial, using Counter creates a dictionary that stores all unique values, which could be memory-intensive compared to alternative approaches.

Solution: Use a more memory-efficient approach with a boolean array for seen values:

def getSneakyNumbers(self, nums: List[int]) -> List[int]:
    n = len(nums) - 2  # Original size should be n
    seen = [False] * n
    result = []
  
    for num in nums:
        if seen[num]:
            result.append(num)
        else:
            seen[num] = True
  
    return result

3. Not Handling Edge Cases

The solution doesn't explicitly handle edge cases like empty arrays or arrays with invalid numbers (outside the range [0, n-1]).

Solution: Add edge case handling:

def getSneakyNumbers(self, nums: List[int]) -> List[int]:
    if not nums or len(nums) < 3:
        return []
  
    n = len(nums) - 2
    frequency_map = Counter(nums)
  
    # Validate all numbers are in valid range
    for num in frequency_map:
        if num < 0 or num >= n:
            raise ValueError(f"Number {num} is outside valid range [0, {n-1}]")
  
    duplicates = [number for number, count in frequency_map.items() if count == 2]
    return duplicates
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

What's the relationship between a tree and a graph?


Recommended Readings

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

Load More