diff --git a/.notes/1365.md b/.notes/1365.md new file mode 100644 index 0000000..a504013 --- /dev/null +++ b/.notes/1365.md @@ -0,0 +1,150 @@ +# 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 (0–100). 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[a−1] — 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.