Skip to content
ΣDSA Patterns
Menu
Language

Meet in the Middle

Guide 3 of 6 · Path 3 of 6

Interactive

Mental model

A worked animation for this problem. Scrub steps or press space to pause; re-tell the invariant out loud.

Step 1 of 6
1
2
3
6

split for MITM

Tallest billboard: rods [1,2,3,6]. Each rod goes left, right, or neither. Equal heights, maximize that height.

Demo preview: These solutions pass the automated test suite but have not been human-reviewed. Treat trade-offs and prose as draft.

Tallest Billboard

Problem (restated)

Assign each rod to the left support, the right support, or neither. The two supports must end at equal height. Maximize that height (0 if impossible). n ≤ 20.

Intuition

Equal supports ⇔ two disjoint subsets with the same sum. 3^n is tight; MITM enumerates 3^{n/2} assignments per half and joins where diffs cancel.

Approaches

Meet in the middle, 3-way diffs

Unverified
Time O(n·3^{n/2})Space O(3^{n/2})

Idea. Split rods. Each half maps diff = left − right → max left height (skip / put left / put right). Join d with −d; combined height is h1 + h2. Keep only the best height per diff.

Walkthrough. [1,2,3,6] → 6 (1+2+3 vs 6). [1,2,3,4,5,6] → 10. [1,2] → 0.

Trade-offs. Knapsack on sum is also viable (n·Σ²) because rods are tiny (≤ 1000); MITM does not depend on value magnitude.

Solution
export function tallestBillboard(rods: number[]): number {
  const mid = rods.length >> 1;

  const diffs = (arr: number[]): Map<number, number> => {
    let dp = new Map<number, number>([[0, 0]]);
    for (const x of arr) {
      const ndp = new Map(dp);
      for (const [d, h] of dp) {
        const left = d + x;
        ndp.set(left, Math.max(ndp.get(left) ?? 0, h + x));
        const right = d - x;
        ndp.set(right, Math.max(ndp.get(right) ?? 0, h));
      }
      dp = ndp;
    }
    return dp;
  };

  const left = diffs(rods.slice(0, mid));
  const right = diffs(rods.slice(mid));
  let ans = 0;
  for (const [d, h] of left) {
    if (right.has(-d)) ans = Math.max(ans, h + right.get(-d)!);
  }
  return ans;
}
export function tallestBillboard(rods: number[]): number {
  const mid = rods.length >> 1;

  const diffs = (arr: number[]): Map<number, number> => {
    let dp = new Map<number, number>([[0, 0]]);
    for (const x of arr) {
      const ndp = new Map(dp);
      for (const [d, h] of dp) {
        const left = d + x;
        ndp.set(left, Math.max(ndp.get(left) ?? 0, h + x));
        const right = d - x;
        ndp.set(right, Math.max(ndp.get(right) ?? 0, h));
      }
      dp = ndp;
    }
    return dp;
  };

  const left = diffs(rods.slice(0, mid));
  const right = diffs(rods.slice(mid));
  let ans = 0;
  for (const [d, h] of left) {
    if (right.has(-d)) ans = Math.max(ans, h + right.get(-d)!);
  }
  return ans;
}

Template connection

Constraint-satisfaction MITM: the join key is the signed height diff instead of a subset sum.

Reflection