196 lines
8.1 KiB
YAML
196 lines
8.1 KiB
YAML
title: Check if Number Has Equal Digit Count and Digit Value
|
|
slug: check-if-number-has-equal-digit-count-and-digit-value
|
|
difficulty: easy
|
|
leetcode_id: 2283
|
|
leetcode_url: https://leetcode.com/problems/check-if-number-has-equal-digit-count-and-digit-value/
|
|
categories:
|
|
- strings
|
|
- hash-tables
|
|
patterns:
|
|
- slug: prefix-sum
|
|
is_optimal: true
|
|
|
|
function_signature: "def digit_count(num: str) -> bool:"
|
|
|
|
test_cases:
|
|
visible:
|
|
- input: { num: "1210" }
|
|
expected: true
|
|
- input: { num: "030" }
|
|
expected: false
|
|
hidden:
|
|
- input: { num: "2020" }
|
|
expected: true
|
|
- input: { num: "0" }
|
|
expected: false
|
|
- input: { num: "10" }
|
|
expected: false
|
|
- input: { num: "21200" }
|
|
expected: true
|
|
- input: { num: "1111" }
|
|
expected: false
|
|
- input: { num: "2100" }
|
|
expected: true
|
|
|
|
description: |
|
|
You are given a **0-indexed** string `num` of length `n` consisting of digits.
|
|
|
|
Return `true` *if for **every** index* `i` *in the range* `0 <= i < n`*, the digit* `i` *occurs* `num[i]` *times in* `num`*, otherwise return* `false`.
|
|
|
|
constraints: |
|
|
- `n == num.length`
|
|
- `1 <= n <= 10`
|
|
- `num` consists only of digits
|
|
|
|
examples:
|
|
- input: 'num = "1210"'
|
|
output: "true"
|
|
explanation: |
|
|
num[0] = '1'. The digit 0 occurs once in num.
|
|
num[1] = '2'. The digit 1 occurs twice in num.
|
|
num[2] = '1'. The digit 2 occurs once in num.
|
|
num[3] = '0'. The digit 3 occurs zero times in num.
|
|
The condition holds true for every index in "1210", so return true.
|
|
- input: 'num = "030"'
|
|
output: "false"
|
|
explanation: |
|
|
num[0] = '0'. The digit 0 should occur zero times, but actually occurs twice in num.
|
|
num[1] = '3'. The digit 1 should occur three times, but actually occurs zero times in num.
|
|
num[2] = '0'. The digit 2 occurs zero times in num.
|
|
The indices 0 and 1 both violate the condition, so return false.
|
|
|
|
explanation:
|
|
intuition: |
|
|
Think of this problem as a **self-describing number** puzzle. Each position in the string tells you how many times that position's index should appear as a digit elsewhere in the string.
|
|
|
|
Imagine the string as a set of rules: position 0 says "the digit 0 must appear exactly `num[0]` times", position 1 says "the digit 1 must appear exactly `num[1]` times", and so on. Your job is to verify that the string follows its own rules.
|
|
|
|
The key insight is that we need to **count the occurrences** of each digit first, then check if each position's value matches the count for its corresponding index. This is a classic counting problem where we build a frequency map and then validate against it.
|
|
|
|
approach: |
|
|
We solve this using a **Counting Approach**:
|
|
|
|
**Step 1: Count digit frequencies**
|
|
|
|
- Create a frequency array or hash map to count how many times each digit (0-9) appears in the string
|
|
- Iterate through the string once to populate these counts
|
|
|
|
|
|
|
|
**Step 2: Validate the self-describing property**
|
|
|
|
- For each index `i` from `0` to `n-1`:
|
|
- Get the expected count from `num[i]` (convert character to integer)
|
|
- Get the actual count of digit `i` from our frequency map
|
|
- If they don't match, return `false`
|
|
|
|
|
|
|
|
**Step 3: Return the result**
|
|
|
|
- If all positions pass validation, return `true`
|
|
|
|
|
|
|
|
This approach works because we separate the problem into two clear phases: counting and validating. The counting phase gives us the ground truth, and the validation phase checks if the string's claims match reality.
|
|
|
|
common_pitfalls:
|
|
- title: Confusing Index and Value
|
|
description: |
|
|
The problem has a subtle twist: at index `i`, the *value* `num[i]` tells us how many times the *digit* `i` should appear.
|
|
|
|
For example, at index 2, if `num[2] = '1'`, this means the digit `2` should appear exactly once in the string — not that the digit `1` should appear twice.
|
|
|
|
Read carefully: we're checking if digit `i` occurs `num[i]` times.
|
|
wrong_approach: "Checking if digit num[i] occurs i times"
|
|
correct_approach: "Checking if digit i occurs num[i] times"
|
|
|
|
- title: Character vs Integer Conversion
|
|
description: |
|
|
Remember that `num` is a string, so `num[i]` gives a character like `'2'`, not the integer `2`.
|
|
|
|
You need to convert: `int(num[i])` in Python, or `num[i] - '0'` in languages like C++ or Java.
|
|
|
|
Forgetting this conversion leads to comparing characters with integers, which will give wrong results or type errors.
|
|
wrong_approach: "Comparing num[i] directly with count"
|
|
correct_approach: "Convert num[i] to integer before comparison"
|
|
|
|
- title: Not Handling All Indices
|
|
description: |
|
|
Since the string has length `n`, we only need to check indices `0` through `n-1`. We only care about digits `0` through `n-1` as well, since larger digits can't be valid indices.
|
|
|
|
However, digits larger than `n-1` appearing in the string is fine — they just won't be checked as indices. The constraint `n <= 10` ensures all digits 0-9 are potentially valid.
|
|
|
|
key_takeaways:
|
|
- "**Self-describing structures**: Some problems define constraints that reference themselves — break these into counting and validation phases"
|
|
- "**Frequency counting pattern**: Building a frequency map first simplifies many validation problems"
|
|
- "**Index vs value awareness**: Pay close attention to what the index represents vs what the value represents"
|
|
- "**Small constraint optimisation**: With `n <= 10`, even O(n^2) would work, but O(n) is cleaner and teaches better habits"
|
|
|
|
time_complexity: "O(n). We iterate through the string twice: once to count frequencies, once to validate."
|
|
space_complexity: "O(1). We use a fixed-size frequency array of 10 elements (for digits 0-9), regardless of input size."
|
|
|
|
solutions:
|
|
- approach_name: Frequency Counting
|
|
is_optimal: true
|
|
code: |
|
|
def digit_count(num: str) -> bool:
|
|
# Count occurrences of each digit (0-9)
|
|
freq = [0] * 10
|
|
for char in num:
|
|
freq[int(char)] += 1
|
|
|
|
# Check if each index i has digit i appearing num[i] times
|
|
for i in range(len(num)):
|
|
expected = int(num[i]) # How many times digit i should appear
|
|
actual = freq[i] # How many times digit i actually appears
|
|
if expected != actual:
|
|
return False
|
|
|
|
return True
|
|
explanation: |
|
|
**Time Complexity:** O(n) — Two passes through the string of length n.
|
|
|
|
**Space Complexity:** O(1) — Fixed array of 10 integers.
|
|
|
|
We first count all digit occurrences, then verify each position's claim. The fixed-size frequency array makes this space-efficient.
|
|
|
|
- approach_name: Counter with Pythonic Check
|
|
is_optimal: true
|
|
code: |
|
|
from collections import Counter
|
|
|
|
def digit_count(num: str) -> bool:
|
|
# Count all digit occurrences
|
|
count = Counter(num)
|
|
|
|
# Check each index: digit i should occur num[i] times
|
|
for i, char in enumerate(num):
|
|
expected = int(char)
|
|
actual = count.get(str(i), 0) # Get count of digit i (as string)
|
|
if expected != actual:
|
|
return False
|
|
|
|
return True
|
|
explanation: |
|
|
**Time Complexity:** O(n) — Counter creation and validation loop.
|
|
|
|
**Space Complexity:** O(k) — Where k is the number of unique digits (at most 10).
|
|
|
|
This approach uses Python's Counter for cleaner counting. Note that we look up `str(i)` since Counter keys are characters, not integers.
|
|
|
|
- approach_name: One-Liner (Pythonic)
|
|
is_optimal: true
|
|
code: |
|
|
from collections import Counter
|
|
|
|
def digit_count(num: str) -> bool:
|
|
count = Counter(num)
|
|
return all(count.get(str(i), 0) == int(c) for i, c in enumerate(num))
|
|
explanation: |
|
|
**Time Complexity:** O(n) — Single pass with generator expression.
|
|
|
|
**Space Complexity:** O(k) — Counter storage for unique digits.
|
|
|
|
A concise one-liner using `all()` with a generator. For each position, we check if the count of that index-as-digit matches the expected value. Elegant but less readable for beginners.
|