diff --git a/work/Blind/deduction.answers.js b/work/Blind/deduction.answers.js new file mode 100644 index 0000000..4d54034 --- /dev/null +++ b/work/Blind/deduction.answers.js @@ -0,0 +1,151 @@ +// ============================================================ +// 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). +// ============================================================ diff --git a/work/Blind/deduction.js b/work/Blind/deduction.js new file mode 100644 index 0000000..f124126 --- /dev/null +++ b/work/Blind/deduction.js @@ -0,0 +1,82 @@ +// ============================================================ +// BLIND DEDUCTION SET — Monday evening, ONE round, then stop. +// The 6 core interview problems, disguised exactly as they'd +// appear Tuesday: no statement, just input => output pairs. +// Rules: deduce the rule, SAY it in one sentence out loud, +// state the plan (freq map? sort? tiebreak?), then implement. +// Do NOT open blind-deduction-answers.js until finished. +// Target: rule stated < 3 min, implemented < 6 min each. +// ============================================================ + +// ---- problem1 ---- +// problem1([8, 1, 2, 2, 3]) => [4, 0, 1, 1, 3] +// problem1([6, 5, 4, 8]) => [2, 1, 0, 3] +// problem1([7, 7, 7, 7]) => [0, 0, 0, 0] +// problem1([3, 1, 2]) => [2, 0, 1] +// problem1([5]) => [0] +// problem1([4, 1, 4, 1]) => [2, 0, 2, 0] +function problem1(arr) { + // your code +} + +// ---- problem2 ---- +// problem2("tree") => "eert" +// problem2("cccaaa") => "aaaccc" +// problem2("Aabb") => "bbaA" +// problem2("z") => "z" +// problem2("bookkeeper") => "eeekkoobpr" +// problem2("mississippi") => "iiiissssppm" +function problem2(str) { + // your code +} + +// ---- problem3 ---- +// problem3([1, 1, 2, 2, 2, 3]) => [3, 1, 1, 2, 2, 2] +// problem3([2, 3, 1, 3, 2]) => [1, 3, 3, 2, 2] +// problem3([-1, 1, -6, 4, 5, -6, 1, 4, 1]) => [5, -1, 4, 4, -6, -6, 1, 1, 1] +// problem3([9]) => [9] +// problem3([5, 5, 4, 4]) => [5, 5, 4, 4] +function problem3(arr) { + // your code +} + +// ---- problem4 ---- +// problem4("leetcode") => 0 +// problem4("loveleetcode") => 2 +// problem4("aabb") => -1 +// problem4("x") => 0 +// problem4("aabbc") => 4 +// problem4("aa") => -1 +function problem4(str) { + // your code +} + +// ---- problem5 ---- +// problem5("anagram", "nagaram") => true +// problem5("rat", "car") => false +// problem5("a", "ab") => false +// problem5("", "") => true +// problem5("aacc", "ccac") => false +// problem5("listen", "silent") => true +function problem5(s, t) { + // your code +} + +// ---- problem6 ---- +// problem6([1, 1, 1, 2, 2, 3], 2) => [1, 2] +// problem6([1], 1) => [1] +// problem6([4, 4, 4, 6, 6, 7, 7, 7, 7], 2) => [7, 4] +// problem6([5, 5, 5, 5], 1) => [5] +// problem6([3, 0, 1, 0], 1) => [0] +// problem6([2, 2, 3, 3, 1], 3) => [2, 3, 1] +function problem6(arr, k) { + // your code +} + +// ---- harness: uncomment per problem after implementing ---- +// console.log(problem1([8, 1, 2, 2, 3]), problem1([4, 1, 4, 1])); +// console.log(problem2("tree"), problem2("bookkeeper")); +// console.log(problem3([2, 3, 1, 3, 2]), problem3([5, 5, 4, 4])); +// console.log(problem4("loveleetcode"), problem4("aabbc")); +// console.log(problem5("anagram", "nagaram"), problem5("aacc", "ccac")); +// console.log(problem6([4, 4, 4, 6, 6, 7, 7, 7, 7], 2), problem6([2, 2, 3, 3, 1], 3)); diff --git a/work/Easy/Array/1365.how-many-numbers-are-smaller-than-the-current-number.js b/work/Easy/Array/1365.how-many-numbers-are-smaller-than-the-current-number.js new file mode 100644 index 0000000..3ed3996 --- /dev/null +++ b/work/Easy/Array/1365.how-many-numbers-are-smaller-than-the-current-number.js @@ -0,0 +1,77 @@ +/* + * 1365. How Many Numbers Are Smaller Than the Current Number + * Difficulty: Easy + * https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/ + * + * ────────────────────────────────────────────────── + * + * Given the array nums, for each nums[i] find out how many numbers in + * the array are smaller than it. That is, for each nums[i] you have to + * count the number of valid j's such that j != i and nums[j] < nums[i]. + * + * Return the answer in an array. + * + * + * + * Example 1: + * + * Input: nums = [8,1,2,2,3] + * Output: [4,0,1,1,3] + * Explanation: + * For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and + * 3). + * For nums[1]=1 does not exist any smaller number than it. + * For nums[2]=2 there exist one smaller number than it (1). + * For nums[3]=2 there exist one smaller number than it (1). + * For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2). + * + * Example 2: + * + * Input: nums = [6,5,4,8] + * Output: [2,1,0,3] + * + * Example 3: + * + * Input: nums = [7,7,7,7] + * Output: [0,0,0,0] + * + * + * + * Constraints: + * + * • 2 <= nums.length <= 500 + * + * • 0 <= nums[i] <= 100 + */ + +/** + * @param {number[]} nums + * @return {number[]} + */ + +var smallerNumbersThanCurrent = function (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 + 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]); +}; diff --git a/work/Easy/Array/1636.sort-array-by-increasing-frequency.js b/work/Easy/Array/1636.sort-array-by-increasing-frequency.js new file mode 100644 index 0000000..2ace9f9 --- /dev/null +++ b/work/Easy/Array/1636.sort-array-by-increasing-frequency.js @@ -0,0 +1,52 @@ +/* + * 1636. Sort Array by Increasing Frequency + * Difficulty: Easy + * https://leetcode.com/problems/sort-array-by-increasing-frequency/ + * + * ────────────────────────────────────────────────── + * + * Given an array of integers nums, sort the array in increasing order + * based on the frequency of the values. If multiple values have the same + * frequency, sort them in decreasing order. + * + * Return the sorted array. + * + * + * + * Example 1: + * + * Input: nums = [1,1,2,2,2,3] + * Output: [3,1,1,2,2,2] + * Explanation: '3' has a frequency of 1, '1' has a frequency of 2, and + * '2' has a frequency of 3. + * + * Example 2: + * + * Input: nums = [2,3,1,3,2] + * Output: [1,3,3,2,2] + * Explanation: '2' and '3' both have a frequency of 2, so they are + * sorted in decreasing order. + * + * Example 3: + * + * Input: nums = [-1,1,-6,4,5,-6,1,4,1] + * Output: [5,-1,4,4,-6,-6,1,1,1] + * + * + * + * Constraints: + * + * • 1 <= nums.length <= 100 + * + * • -100 <= nums[i] <= 100 + */ + +/** + * @param {number[]} nums + * @return {number[]} + */ +var frequencySort = function (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); +}; diff --git a/work/Easy/Hash Table/387.first-unique-character-in-a-string.js b/work/Easy/Hash Table/387.first-unique-character-in-a-string.js new file mode 100644 index 0000000..d849c6d --- /dev/null +++ b/work/Easy/Hash Table/387.first-unique-character-in-a-string.js @@ -0,0 +1,59 @@ +/* + * 387. First Unique Character in a String + * Difficulty: Easy + * https://leetcode.com/problems/first-unique-character-in-a-string/ + * + * ────────────────────────────────────────────────── + * + * Given a string s, find the first non-repeating character in it and + * return its index. If it does not exist, return -1. + * + * + * + * Example 1: + * + * Input: s = "leetcode" + * + * Output: 0 + * + * Explanation: + * + * The character 'l' at index 0 is the first character that does not + * occur at any other index. + * + * Example 2: + * + * Input: s = "loveleetcode" + * + * Output: 2 + * + * Example 3: + * + * Input: s = "aabb" + * + * Output: -1 + * + * + * + * Constraints: + * + * • 1 <= s.length <= 10^5 + * + * • s consists of only lowercase English letters. + */ + +/** + * @param {string} s + * @return {number} + */ +var firstUniqChar = function (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; +}; diff --git a/work/Medium/Array/347.top-k-frequent-elements.js b/work/Medium/Array/347.top-k-frequent-elements.js new file mode 100644 index 0000000..3936999 --- /dev/null +++ b/work/Medium/Array/347.top-k-frequent-elements.js @@ -0,0 +1,62 @@ +/* + * 347. Top K Frequent Elements + * Difficulty: Medium + * https://leetcode.com/problems/top-k-frequent-elements/ + * + * ────────────────────────────────────────────────── + * + * Given an integer array nums and an integer k, return the k most + * frequent elements. You may return the answer in any order. + * + * + * + * Example 1: + * + * Input: nums = [1,1,1,2,2,3], k = 2 + * + * Output: [1,2] + * + * Example 2: + * + * Input: nums = [1], k = 1 + * + * Output: [1] + * + * Example 3: + * + * Input: nums = [1,2,1,2,1,2,3,1,3,2], k = 2 + * + * Output: [1,2] + * + * + * + * Constraints: + * + * • 1 <= nums.length <= 10^5 + * + * • -10^4 <= nums[i] <= 10^4 + * + * • k is in the range [1, the number of unique elements in the array]. + * + * • It is guaranteed that the answer is unique. + * + * + * + * Follow up: Your algorithm's time complexity must be better than O(n + * log n), where n is the array's size. + */ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +var topKFrequent = function (nums, k) { + const freq = {}; + for (let n of nums) freq[n] = (freq[n] || 0) + 1; + + return Object.keys(freq) + .map(Number) + .sort((a, b) => freq[b] - freq[a]) + .slice(0, k); +}; diff --git a/work/Medium/Hash Table/451.sort-characters-by-frequency.js b/work/Medium/Hash Table/451.sort-characters-by-frequency.js new file mode 100644 index 0000000..0357d5c --- /dev/null +++ b/work/Medium/Hash Table/451.sort-characters-by-frequency.js @@ -0,0 +1,64 @@ +/* + * 451. Sort Characters By Frequency + * Difficulty: Medium + * https://leetcode.com/problems/sort-characters-by-frequency/ + * + * ────────────────────────────────────────────────── + * + * Given a string s, sort it in decreasing order based on the frequency + * of the characters. The frequency of a character is the number of times + * it appears in the string. + * + * Return the sorted string. If there are multiple answers, return any + * of them. + * + * + * + * Example 1: + * + * Input: s = "tree" + * Output: "eert" + * Explanation: 'e' appears twice while 'r' and 't' both appear once. + * So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also + * a valid answer. + * + * Example 2: + * + * Input: s = "cccaaa" + * Output: "aaaccc" + * Explanation: Both 'c' and 'a' appear three times, so both "cccaaa" + * and "aaaccc" are valid answers. + * Note that "cacaca" is incorrect, as the same characters must be + * together. + * + * Example 3: + * + * Input: s = "Aabb" + * Output: "bbAa" + * Explanation: "bbaA" is also a valid answer, but "Aabb" is incorrect. + * Note that 'A' and 'a' are treated as two different characters. + * + * + * + * Constraints: + * + * • 1 <= s.length <= 5 * 10^5 + * + * • s consists of uppercase and lowercase English letters and digits. + */ + +/** + * @param {string} s + * @return {string} + */ +var frequencySort = function (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 + return s + .split("") + .sort((a, b) => freq[b] - freq[a] || a.localeCompare(b)) + .join(""); +};