// ============================================================ // ANSWER KEY — open only after narrating all 6 out loud. // Solutions match your repo style exactly: // ~/Developer/github.com/prdlk/leetcode/work/Default // (object freq maps, (freq[n] || 0) + 1, same shapes) // ============================================================ // problem1 = LC 1365 — How Many Numbers Are Smaller Than Current // (your file: Easy/Array/1365...js — this IS your solution) // RULE: "output[i] = count of elements strictly smaller than arr[i]; // ties don't count as smaller (that's the [7,7,7,7] example)." function problem1(nums) { // Step 1: Begin by initializing a [Frequency Map] const freq = {}; for (let n of nums) freq[n] = (freq[n] || 0) + 1; // Step 2: Sort the numbers by ascending order const sorted = Object.keys(freq).sort((a, b) => a - b); // Step 3: Init a count of numbers smaller than the active number let count = 0; // Step 4: Init a map to track number of values smaller for each number const smaller = {}; // Step 5: Iterate over the sorted list for (let num of sorted) { // Set count for active number — BEFORE adding own frequency, // so duplicates only see values strictly below them smaller[num] = count; // Update the count by frequency count += freq[num]; } // Step 6: Use original list and find number of smaller values than it return nums.map((n) => smaller[n]); } // Narration reminders: // - "record before adding" is WHY [7,7,7,7] => [0,0,0,0] // - Object.keys returns strings; (a, b) => a - b coerces numerically // - quick brute-force alternative if short on time: // nums.map((n) => nums.filter((m) => m < n).length) // problem2 = LC 451 — Sort Characters By Frequency (+ alpha tiebreak) // (your file: Medium/Hash Table/451...js — same, tiebreak included) // RULE: "rebuild the string most-frequent chars first; equal counts // break alphabetically." // DISCRIMINATOR: "bookkeeper" — e:3, then k:2/o:2 tie -> k before o // = alphabetical, NOT input order (o appeared first in the input!). function problem2(s) { // count the frequency of each character const freq = {}; for (let c of s) freq[c] = (freq[c] || 0) + 1; // sort the characters by frequency, ties alphabetical return s .split("") .sort((a, b) => freq[b] - freq[a] || a.localeCompare(b)) .join(""); } // Note vs your repo file: identical. localeCompare orders lowercase // before uppercase ("bbaA"), which is what the drill examples use. // LC 451 proper accepts any tie order — the tiebreak is the // interview twist Jim's source described. // problem3 = LC 1636 — Sort Array by Increasing Frequency // (your file: Easy/Array/1636...js — this IS your solution) // RULE: "sort by frequency ascending; ties by VALUE DESCENDING." // DISCRIMINATOR: [2,3,1,3,2] -> 2 and 3 both appear twice, 3 first. function problem3(nums) { const freq = {}; for (let n of nums) freq[n] = (freq[n] || 0) + 1; return nums.sort((a, b) => freq[a] - freq[b] || b - a); } // The idiom to say out loud: "primary key OR tiebreak — when the // frequency difference is 0 (falsy), JS falls through to b - a." // problem4 = LC 387 — First Unique Character // (your file: Easy/Hash Table/387...js — this IS your solution) // RULE: "index of the first character appearing exactly once; -1 if none." // SHAPE TELL: output is a NUMBER, not an array. function problem4(s) { const freq = {}; for (let c of s) freq[c] = (freq[c] || 0) + 1; for (let i = 0; i < s.length; i++) { if (freq[s[i]] === 1) { return i; } } return -1; } // Say it: "two passes — I can't know a char is unique until I've // seen the whole string." // problem5 = LC 242 — Valid Anagram // (not in your repo yet — written in your exact style) // RULE: "true iff both strings have the same characters with the // same counts." // DISCRIMINATOR: ("aacc", "ccac") -> same char SET {a,c}, different // counts -> false. Kills set-equality. function problem5(s, t) { if (s.length !== t.length) return false; const freq = {}; for (let c of s) freq[c] = (freq[c] || 0) + 1; // walk t, spending counts down; a missing/exhausted char fails for (let c of t) { if (!freq[c]) return false; freq[c]--; } return true; } // The length guard up front is what lets count-down work without a // final "all zeros" pass. // problem6 = LC 347 — Top K Frequent Elements // (your file: Medium/Array/347...js — this IS your solution) // RULE: "return the k values that appear most often, most frequent // first." // SHAPE TELL: second argument k controls output length. // EDGE: [3,0,1,0] k=1 => [0] — value 0 is falsy but valid. function problem6(nums, k) { const freq = {}; for (let n of nums) freq[n] = (freq[n] || 0) + 1; return Object.keys(freq) .map(Number) // Object.keys gave us strings — convert back .sort((a, b) => freq[b] - freq[a]) .slice(0, k); } // The .map(Number) is the classic gotcha to mention: without it you // return ["1","2"] instead of [1,2]. // ============================================================ // THE HAMMER (all six are this skeleton): // 1. BUILD -> const freq = {}; for (let x of input) // freq[x] = (freq[x] || 0) + 1; // 2. ORDER -> sort keys/elements by the criterion the pattern demands // 3. DERIVE -> compute what each key maps to (count / rank / index) // 4. EMIT -> map back to input order / rebuild string / slice k // // SELF-SCORE per problem: // Rule stated in one sentence, verified vs ALL examples: /1 // Tiebreak/edge named BEFORE coding (the discriminator): /1 // Working code, narrated while typing: /1 // 15+/18 = ready. Misses tell you what to re-drill Tuesday // morning (max 2 reps, then stop — rest beats an 11th rep). // ============================================================