20. Count Numbers Containing Specific Digits

βœ… GFG solution to the Count Numbers Containing Specific Digits problem: find total n-digit numbers containing at least one digit from given array using complement counting technique. πŸš€

The problem can be found at the following link: πŸ”— Question Link

🧩 Problem Description

You are given an integer n representing the number of digits in a number, and an array arr[] containing digits from 0 to 9. Your task is to count how many n-digit positive integers can be formed such that at least one digit from the array arr[] appears in the number.

An n-digit positive integer is a number that has exactly n digits and doesn't start with 0 (except when n=1, where single digit 0 is not considered a positive integer).

πŸ“˜ Examples

Example 1

Input: n = 1, arr[] = [1, 2, 3]
Output: 3
Explanation: Only the single-digit numbers [1, 2, 3] satisfy the condition.

Example 2

Input: n = 2, arr[] = [3, 5]
Output: 34
Explanation: There are a total of 34 two-digit numbers which contain at least one out of [3, 5].

πŸ”’ Constraints

  • $1 \le n \le 9$

  • $1 \le \text{arr.size()} \le 10$

  • $0 \le \text{arr}[i] \le 9$

βœ… My Approach

The optimal approach uses Complement Counting technique with Bit Manipulation to efficiently calculate the result:

Complement Counting + Bit Manipulation

  1. Core Insight:

    • Instead of directly counting numbers with at least one digit from arr[], we count numbers with NO digits from arr[] and subtract from total.

    • Formula: Result = Total n-digit numbers - Numbers with forbidden digits only

  2. Calculate Total n-digit Numbers:

    • For n=1: Total = 9 (digits 1-9, excluding 0)

    • For n>1: Total = 9 Γ— 10^(n-1) (first digit: 1-9, remaining: 0-9)

  3. Track Forbidden Digits:

    • Use bit manipulation to mark allowed digits from arr[]

    • Count forbidden digits: forbidden = 10 - |allowed_digits|

    • Count non-zero forbidden digits: nonZeroForbidden = 9 - |allowed_nonzero_digits|

  4. Calculate Invalid Numbers:

    • For n=1: Invalid = count of non-zero forbidden digits

    • For n>1: Invalid = nonZeroForbidden Γ— forbidden^(n-1)

  5. Final Result:

    • Return Total - Invalid

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n + |arr|), where n is the number of digits and |arr| is the size of the input array. We iterate through the array once to mark allowed digits and perform n-1 multiplications for power calculation.

  • Expected Auxiliary Space Complexity: O(1), as we only use a constant amount of additional space for bit masks and counting variables, regardless of input size.

πŸ§‘β€πŸ’» Code (C++)

⚑ View Alternative Approaches with Code and Analysis

πŸ“Š 2️⃣ Bit Manipulation with Precomputed Powers

πŸ’‘ Algorithm Steps:

  1. Use bit manipulation to track forbidden digits

  2. Precompute powers to avoid repeated calculations

  3. Single pass calculation for efficiency

  4. Bitwise operations for faster digit checking

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n + |arr|)

  • Auxiliary Space: πŸ’Ύ O(1) - constant space usage

βœ… Why This Approach?

  • Eliminates function call overhead

  • Linear time power calculation

  • Direct boolean array lookup

πŸ“Š 3️⃣ Mathematical Formula Approach

πŸ’‘ Algorithm Steps:

  1. Calculate forbidden digits in single pass

  2. Use mathematical formula for power calculation

  3. Direct computation without loops

  4. Optimized for competitive programming

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(|arr| + log n) due to pow function

  • Auxiliary Space: πŸ’Ύ O(|arr|) for the unordered_set

βœ… Why This Approach?

  • Single bit mask for all digits

  • Built-in popcount for efficiency

  • Minimal memory footprint

πŸ“Š 4️⃣ Iterative Power Calculation

πŸ’‘ Algorithm Steps:

  1. Count forbidden digits using array indexing

  2. Iterative power calculation with accumulation

  3. Early termination optimization

  4. Cache-friendly memory access

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n + |arr|)

  • Auxiliary Space: πŸ’Ύ O(1) - fixed array size

βœ… Why This Approach?

  • Optimized loop structure

  • Reduced multiplication operations

  • Better cache locality

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

πŸ” Bit Manipulation

🟒 O(n + |arr|)

🟒 O(1)

πŸš€ Fastest bit operations

πŸ’Ύ Requires bit manipulation knowledge

πŸ”Ί Precomputed Powers

🟒 O(n + |arr|)

🟒 O(1)

πŸ”§ No function call overhead

πŸ’Ύ Slightly more complex logic

⏰ Mathematical Formula

🟑 O(|arr| + log n)

🟑 O(|arr|)

πŸš€ Minimal memory usage

πŸ”„ Requires mathematical insight

πŸ“Š Iterative Calculation

🟒 O(n + |arr|)

🟒 O(1)

⚑ Cache-friendly access

πŸ”§ More complex loop structure

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

⚑ Competitive Programming

πŸ₯‡ Bit Manipulation

β˜…β˜…β˜…β˜…β˜…

πŸ“Š General Purpose

πŸ₯ˆ Precomputed Powers

β˜…β˜…β˜…β˜…β˜†

🎯 Memory Constrained

πŸ₯‰ Mathematical Formula

β˜…β˜…β˜…β˜…β˜†

πŸš€ Educational/Readable

πŸ… Iterative Calculation

β˜…β˜…β˜…β˜†β˜†

πŸ§‘β€πŸ’» Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated