Files
leetcode/.notes/1365.md
T

151 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 1365. How Many Numbers Are Smaller Than the Current Number
**Difficulty:** Easy
**URL:** https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/
**Topics:** Array, Hash Table, Sorting, Counting Sort
---
## The One Insight That Makes This Work
> If I know how many times each value appears, and I add those counts up from left to right, then `prefix[v]` tells me **how many elements are ≤ v** — instantly, for any v.
That's it. Everything below is just executing this idea.
---
## Step 1: Spot the Signal
Read the constraints:
```
0 <= nums[i] <= 100
```
Values are bounded to a tiny range (0100). This is the **flashing neon sign** that says: don't sort, don't nest loops — build a frequency array indexed by value.
**Rule of thumb:** value range ≤ ~10⁶ and you need counting/ranking? Frequency array.
---
## Step 2: Count Every Value (the "bucket" pass)
Make an array with one slot per possible value. Walk the input once. Each number votes for its own slot.
```javascript
const freq = new Array(101).fill(0); // slots for values 0..100
for (const x of nums) freq[x]++;
```
For `nums = [8, 1, 2, 2, 3]`:
```
value: 0 1 2 3 4 5 6 7 8 ...
freq: 0 1 2 1 0 0 0 0 1 ...
```
Read it as: "one 1, two 2s, one 3, one 8."
---
## Step 3: Prefix Sum (the magic pass)
Now transform `freq` in place: each slot becomes itself **plus everything before it**.
```javascript
for (let i = 1; i < 101; i++) freq[i] += freq[i - 1];
```
Same example after the pass:
```
value: 0 1 2 3 4 5 6 7 8 ...
freq: 0 1 3 4 4 4 4 4 5 ...
```
New meaning: `freq[v]` = **count of elements ≤ v**.
- `freq[3] = 4` → four numbers are ≤ 3 (they are 1, 2, 2, 3) ✓
- `freq[7] = 4` → still four numbers ≤ 7 ✓
---
## Step 4: Answer Queries in O(1)
"How many numbers are **strictly smaller** than x?" is the same question as "how many numbers are **≤ x 1**?"
```javascript
return nums.map((x) => (x === 0 ? 0 : freq[x - 1]));
```
The `x === 0` guard exists because nothing can be smaller than the minimum possible value — and `freq[-1]` would be `undefined`.
Trace on `[8, 1, 2, 2, 3]`:
| x | lookup | answer |
|---|--------|--------|
| 8 | freq[7] | 4 |
| 1 | freq[0] | 0 |
| 2 | freq[1] | 1 |
| 2 | freq[1] | 1 |
| 3 | freq[2] | 3 |
`[4, 0, 1, 1, 3]`
---
## Full Solution
```javascript
var smallerNumbersThanCurrent = function (nums) {
// 1. Bucket counts
const freq = new Array(101).fill(0);
for (const x of nums) freq[x]++;
// 2. Prefix sum: freq[v] = count of elements <= v
for (let i = 1; i < 101; i++) freq[i] += freq[i - 1];
// 3. Strictly smaller than x == count of elements <= x-1
return nums.map((x) => (x === 0 ? 0 : freq[x - 1]));
};
```
**Complexity:** O(n + k) time, O(k) space, where k = value range (101 here). No sort, no log factor.
---
## The Reusable Pattern (memorize this shape)
```
1. BUCKET — freq[value]++ for every element
2. PREFIX — freq[i] += freq[i-1] left to right
3. QUERY — freq[v] answers "how many ≤ v" in O(1)
freq[v-1] answers "how many < v"
n - freq[v] answers "how many > v"
```
### Where else this exact shape shows up
| Problem | Same pattern, different query |
|---|---|
| **Counting Sort** | Prefix sums become final sorted positions |
| **LC 315 / rank queries** | "How many smaller" is literally a rank |
| **LC 1122 Relative Sort Array** | Bucket + walk buckets in order |
| **Radix sort digit pass** | Bucket by digit, prefix for placement |
| **Histogram percentiles** | freq[v] / n = percentile of v |
| **"How many in range [a, b]?"** | freq[b] freq[a1] — the prefix subtraction trick |
### The generalization ladder
- Values bounded and small → **frequency array** (this pattern)
- Values huge but few distinct → **coordinate compression** first, then this pattern
- Need updates between queries → upgrade prefix array to a **Fenwick tree (BIT)** — same idea, log-time updates
---
## Common Mistakes
1. **Returning `freq[x]` instead of `freq[x-1]`** — that counts elements ≤ x (including x itself and its duplicates). Off-by-one between "≤" and "<" is where this pattern bites.
2. **Forgetting the `x === 0` edge** — smallest possible value has nothing below it.
3. **Sizing the array to `nums.length` instead of the value range** — the buckets are indexed by *value*, not position.