mirror of
https://github.com/prdlk/leetcode.git
synced 2026-08-02 09:21:40 +00:00
init(work): add JavaScript pattern recognition drills
This commit is contained in:
@@ -0,0 +1,211 @@
|
|||||||
|
// ============================================================
|
||||||
|
// PART A FINAL DRILL — Tuesday morning, before 11:30am.
|
||||||
|
// 8 snippets covering the most likely categories:
|
||||||
|
// nested loops + string accumulation, reference vs copy,
|
||||||
|
// sort() defaults, slice/immutability/off-by-one,
|
||||||
|
// Object.keys strings, splice-while-iterating,
|
||||||
|
// hidden-space parity, string coercion.
|
||||||
|
//
|
||||||
|
// RULES (same as the real thing):
|
||||||
|
// 1. No paper. No running the code until AFTER you answer.
|
||||||
|
// 2. For each snippet, deliver the full narration OUT LOUD:
|
||||||
|
// signature -> structures -> trace -> pattern name -> EXACT output.
|
||||||
|
// 3. Then scroll to the ANSWER KEY at the bottom and check.
|
||||||
|
// 4. Log any miss against the gotcha taxonomy.
|
||||||
|
//
|
||||||
|
// Target: < 90 seconds per snippet. Do NOT peek early.
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 1: nested loop + string accumulation ----
|
||||||
|
function s1(str) {
|
||||||
|
let out = "";
|
||||||
|
for (let i = str.length - 1; i >= 0; i--) {
|
||||||
|
for (let j = 0; j < i; j++) out += "*";
|
||||||
|
out += str[i];
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
// console.log(s1("abc"));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 2: reference vs shallow copy ----
|
||||||
|
function s2() {
|
||||||
|
const a = [1, 2, 3];
|
||||||
|
const b = a;
|
||||||
|
const c = [...a];
|
||||||
|
b.push(4);
|
||||||
|
c.push(5);
|
||||||
|
return [a.length, b.length, c.length];
|
||||||
|
}
|
||||||
|
// console.log(s2());
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 3: sort() default behavior ----
|
||||||
|
function s3(arr) {
|
||||||
|
arr.sort();
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
// console.log(s3([5, 100, 25, 3]));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 4: slice + string immutability + off-by-one ----
|
||||||
|
function s4(str) {
|
||||||
|
str.slice(0, 3);
|
||||||
|
const tail = str.slice(-2);
|
||||||
|
return tail + str.slice(1, 2);
|
||||||
|
}
|
||||||
|
// console.log(s4("planet"));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 5: Object.keys returns strings ----
|
||||||
|
function s5(nums) {
|
||||||
|
const freq = {};
|
||||||
|
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
|
||||||
|
const keys = Object.keys(freq);
|
||||||
|
return keys[0] + keys[1];
|
||||||
|
}
|
||||||
|
// console.log(s5([9, 9, 30, 30]));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 6: splice while iterating ----
|
||||||
|
function s6(arr) {
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i] < 0) arr.splice(i, 1);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
// console.log(s6([-1, -2, 3, -4, -5]));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 7: hidden character parity ----
|
||||||
|
function s7(str) {
|
||||||
|
let out = "";
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
out += i % 2 === 0 ? str[i] : "_";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
// console.log(s7("go far"));
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SNIPPET 8: string coercion mid-loop ----
|
||||||
|
function s8(arr) {
|
||||||
|
let total = 0;
|
||||||
|
for (let x of arr) total += x;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
// console.log(s8([1, 2, "3", 4]));
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// S T O P.
|
||||||
|
//
|
||||||
|
// Narrate all 8 out loud first. Exact outputs stated.
|
||||||
|
// Then read the answer key below and check yourself.
|
||||||
|
//
|
||||||
|
// ============================================================
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
// ---- ANSWER KEY ----
|
||||||
|
//
|
||||||
|
// SNIPPET 1 -> "**c*ba"
|
||||||
|
// Loop runs BACKWARDS (i from 2 down to 0). Each pass pads
|
||||||
|
// i stars, then appends str[i]:
|
||||||
|
// i=2: "**" + "c" -> "**c"
|
||||||
|
// i=1: "*" + "b" -> "**c*b"
|
||||||
|
// i=0: (no stars) + "a" -> "**c*ba"
|
||||||
|
// Traps: reverse iteration direction + star count comes from
|
||||||
|
// the INDEX, not the character. Pattern name: "reverse walk
|
||||||
|
// with index-sized padding."
|
||||||
|
// Narration line: "The outer loop descends, so the last
|
||||||
|
// character is emitted first."
|
||||||
|
//
|
||||||
|
// SNIPPET 2 -> [4, 4, 4]
|
||||||
|
// b = a is an ALIAS (same array). c = [...a] is a real copy
|
||||||
|
// taken BEFORE the pushes. b.push(4) grows a AND b to 4.
|
||||||
|
// c was [1,2,3], its own push(5) grows it to 4.
|
||||||
|
// All three read 4 — for two different reasons. If you said
|
||||||
|
// [4, 4, 5] you forgot c was copied before b.push. If you
|
||||||
|
// said [3, 4, 4] you missed the alias.
|
||||||
|
// Narration line: "Assignment aliases; spread copies — and
|
||||||
|
// the copy freezes the state at the moment it's taken."
|
||||||
|
//
|
||||||
|
// SNIPPET 3 -> [100, 25, 3, 5]
|
||||||
|
// Default sort converts to STRINGS: "100" < "25" < "3" < "5"
|
||||||
|
// lexicographically (compares char by char: "1" < "2" < "3"
|
||||||
|
// < "5"). Also note: sort() MUTATES arr in place and returns
|
||||||
|
// the same reference.
|
||||||
|
// Narration line: "No comparator, so JavaScript sorts these
|
||||||
|
// as strings — 100 comes first because the character '1' is
|
||||||
|
// smallest."
|
||||||
|
//
|
||||||
|
// SNIPPET 4 -> "etl"
|
||||||
|
// Line 1 is a DECOY: strings are immutable and the slice
|
||||||
|
// result is thrown away — str is unchanged.
|
||||||
|
// str.slice(-2) = last two chars = "et".
|
||||||
|
// str.slice(1, 2) = index 1 only (end-exclusive) = "l".
|
||||||
|
// "et" + "l" = "etl".
|
||||||
|
// Traps: the dead line, negative slice, end-exclusivity.
|
||||||
|
// Narration line: "The first slice does nothing — the result
|
||||||
|
// isn't assigned. Strings are immutable."
|
||||||
|
//
|
||||||
|
// SNIPPET 5 -> "930"
|
||||||
|
// freq = {9: 2, 30: 2}. Object.keys returns ["9", "30"] —
|
||||||
|
// STRINGS, in ascending numeric order (JS orders integer-like
|
||||||
|
// keys numerically). "9" + "30" is string CONCATENATION,
|
||||||
|
// not addition: "930". If you said 39, you added numbers
|
||||||
|
// that were never numbers.
|
||||||
|
// Narration line: "Object.keys always returns strings, so
|
||||||
|
// plus means concatenate here."
|
||||||
|
//
|
||||||
|
// SNIPPET 6 -> [-2, 3, -5]
|
||||||
|
// The splice-while-iterating bug, adjacent-negatives flavor:
|
||||||
|
// i=0: -1 removed, everything shifts left -> [-2, 3, -4, -5]
|
||||||
|
// ...but i increments to 1, so -2 (now at index 0)
|
||||||
|
// is SKIPPED.
|
||||||
|
// i=1: 3, not negative, stays.
|
||||||
|
// i=2: -4 removed -> [-2, 3, -5]; -5 slides to index 2,
|
||||||
|
// i increments to 3, past the end. -5 SKIPPED.
|
||||||
|
// Every removal skips its right neighbor. Fix if asked:
|
||||||
|
// iterate backwards, or use filter.
|
||||||
|
// Narration line: "Each splice shifts the array left while i
|
||||||
|
// still moves right, so the element after every removal gets
|
||||||
|
// skipped."
|
||||||
|
//
|
||||||
|
// SNIPPET 7 -> "g_ _a_"
|
||||||
|
// "go far" = g(0) o(1) ' '(2) f(3) a(4) r(5).
|
||||||
|
// Even indices kept, odd replaced with underscore:
|
||||||
|
// g, _, ' ', _, a, _ -> "g_ _a_"
|
||||||
|
// The trap: the SPACE sits at an even index, so it's KEPT —
|
||||||
|
// the middle of the output is underscore-space-underscore,
|
||||||
|
// which looks wrong but isn't. Spaces are characters. They
|
||||||
|
// have indices.
|
||||||
|
// Narration line: "Index 2 is the space and 2 is even, so
|
||||||
|
// the space survives."
|
||||||
|
//
|
||||||
|
// SNIPPET 8 -> "334"
|
||||||
|
// total starts as NUMBER 0:
|
||||||
|
// 0 + 1 = 1, 1 + 2 = 3 (still numbers)
|
||||||
|
// 3 + "3" = "33" (+ with a string CONCATENATES,
|
||||||
|
// and total is now a STRING)
|
||||||
|
// "33" + 4 = "334"
|
||||||
|
// One string element permanently flips the accumulator's
|
||||||
|
// type. Everything after it concatenates.
|
||||||
|
// Narration line: "The plus operator concatenates the moment
|
||||||
|
// either side is a string — and the poison spreads."
|
||||||
|
//
|
||||||
|
// ============================================================
|
||||||
|
// SCORING: 8/8 = ready. 6-7 = re-trace the misses out loud
|
||||||
|
// once and you're ready. Same gotcha missed twice = say that
|
||||||
|
// taxonomy row out loud three times, then stop.
|
||||||
|
//
|
||||||
|
// To verify any answer for real: uncomment its console.log
|
||||||
|
// and run `node partA-final-drill.js`.
|
||||||
|
//
|
||||||
|
// After this: cheatsheet once, decision rule out loud,
|
||||||
|
// close the laptop. 11:30 is yours.
|
||||||
|
// ============================================================
|
||||||
Reference in New Issue
Block a user