πŸ”‘ 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

PatternTimeSpace
Frequency mapO(n)O(k)
Two-sumO(n)O(n)
Prefix sum mapO(n)O(n)
Sliding window + freqO(n)O(k)
Group by keyO(n Β· k log k)O(n Β· k)
Index as hashO(n)O(1)