Meet-in-the-middle (MitM) splits the problem into two halves, enumerates partial results for each half, and then combines them efficiently. It reduces O(c^n) brute force to roughly O(c^{n/2}) time and memory, often using sorting, hashing, or two-pointers.
// MitM subset sum: does any subset sum to T?
function subsetSumMitM(a, T) {
const n = a.length, m = n >> 1;
const L = a.slice(0, m), R = a.slice(m);
const sumsL = [];
const sumsR = [];
// enumerate all sums of left half
for (let mask = 0; mask < (1 << L.length); mask++) {
let s = 0; for (let i = 0; i < L.length; i++) if (mask & 1 << i) s += L[i];
sumsL.push(s);
}
// enumerate all sums of right half
for (let mask = 0; mask < (1 << R.length); mask++) {
let s = 0; for (let i = 0; i < R.length; i++) if (mask & 1 << i) s += R[i];
sumsR.push(s);
}
sumsR.sort((x,y) => x - y);
for (const s of sumsL) {
const need = T - s;
// binary search for need in sumsR
let l = 0, r = sumsR.length - 1;
while (l <= r) {
const m = l + ((r - l) >> 1);
if (sumsR[m] === need) return true;
if (sumsR[m] < need) l = m + 1; else r = m - 1;
}
}
return false;
}
// 4-sum in O(n^2 log n) using MitM
function fourSumExists(a, T) {
const pairs = [];
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j < a.length; j++) {
pairs.push(a[i] + a[j]);
}
}
pairs.sort((x,y) => x - y);
for (let i = 0; i < pairs.length; i++) {
const need = T - pairs[i];
// binary search need
let l = 0, r = pairs.length - 1;
while (l <= r) {
const m = l + ((r - l) >> 1);
if (pairs[m] === need) return true;
if (pairs[m] < need) l = m + 1; else r = m - 1;
}
}
return false;
}