π JavaScript Hashing Patterns
Pattern 1 β Frequency Map
// Anagram check
function isAnagram(s, t) {
if (s.length !== t.length) return false;
const freq = new Map();
for (const c of s) freq.set(c, (freq.get(c) ?? 0) + 1);
for (const c of t) {
if (!freq.has(c) || freq.get(c) === 0) return false;
freq.set(c, freq.get(c) - 1);
}
return true;
}
Pattern 2 β Complement Lookup
function twoSum(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const comp = target - nums[i];
if (map.has(comp)) return [map.get(comp), i];
map.set(nums[i], i);
}
return [];
}
Pattern 3 β Prefix Sum + Map
function subarraySum(nums, k) {
const map = new Map([[0, 1]]);
let sum = 0, count = 0;
for (const n of nums) {
sum += n;
count += map.get(sum - k) ?? 0;
map.set(sum, (map.get(sum) ?? 0) + 1);
}
return count;
}
Pattern 4 β Sliding Window + Frequency
// Find all anagram start indices
function findAnagrams(s, p) {
if (s.length < p.length) return [];
const need = {}, have = {}, result = [];
for (const c of p) need[c] = (need[c] ?? 0) + 1;
for (let i = 0; i < p.length; i++) have[s[i]] = (have[s[i]] ?? 0) + 1;
let matched = 0;
for (const c in need) if ((have[c] ?? 0) === need[c]) matched++;
if (matched === Object.keys(need).length) result.push(0);
for (let i = p.length; i < s.length; i++) {
const r = s[i]; have[r] = (have[r] ?? 0) + 1;
if (need[r] !== undefined) {
if (have[r] === need[r]) matched++;
else if (have[r] === need[r] + 1) matched--;
}
const l = s[i - p.length]; have[l]--;
if (need[l] !== undefined) {
if (have[l] === need[l]) matched++;
else if (have[l] === need[l] - 1) matched--;
}
if (matched === Object.keys(need).length) result.push(i - p.length + 1);
}
return result;
}
Pattern 5 β Group By Key
function groupAnagrams(strs) {
const map = new Map();
for (const s of strs) {
const key = s.split('').sort().join('');
if (!map.has(key)) map.set(key, []);
map.get(key).push(s);
}
return [...map.values()];
}
Pattern 6 β Index as Hash (In-Place)
function firstMissingPositive(nums) {
const n = nums.length;
for (let i = 0; i < n; i++) {
while (nums[i] >= 1 && nums[i] <= n && nums[nums[i]-1] !== nums[i])
[nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]];
}
for (let i = 0; i < n; i++) if (nums[i] !== i + 1) return i + 1;
return n + 1;
}
Pattern 7 β Dual Map (Bijection)
function isIsomorphic(s, t) {
const st = new Map(), ts = new Map();
for (let i = 0; i < s.length; i++) {
const cs = s[i], ct = t[i];
if (st.has(cs) && st.get(cs) !== ct) return false;
if (ts.has(ct) && ts.get(ct) !== cs) return false;
st.set(cs, ct); ts.set(ct, cs);
}
return true;
}
Complexity Summary
| Pattern | Time | Space |
| Frequency map | O(n) | O(k) |
| Two-sum | O(n) | O(n) |
| Prefix sum map | O(n) | O(n) |
| Sliding window + freq | O(n) | O(k) |
| Group by key | O(n Β· k log k) | O(n Β· k) |
| Index as hash | O(n) | O(1) |