Tallest Billboard Problem

Problem

You are installing a billboard and want it to have the largest height. The billboard will have two steel supports, one on each side. Each steel support must be an equal height.

You are given a collection of rods that can be welded together. For example, if you have rods of lengths 1, 2, and 3, you can weld them together to make a support of length 6.

Return the largest possible height of your billboard installation. If you cannot support the billboard, return 0.

Examples

Example 1:

1
2
3
Input: rods = [1,2,3,6]
Output: 6
Explanation: We have two disjoint subsets {1,2,3} and {6}, which have the same sum = 6.

Example 2:

1
2
3
Input: rods = [1,2,3,4,5,6]
Output: 10
Explanation: We have two disjoint subsets {2,3,5} and {4,6}, which have the same sum = 10.

Example 3:

1
2
3
Input: rods = [1,2]
Output: 0
Explanation: The billboard cannot be supported, so we return 0.

Solution

Method 1 – Dynamic Programming with Hash Map

Intuition

We want to split rods into two groups with equal height and maximize that height. We use dynamic programming with a hash map to track all possible differences between two groups and the maximum sum for each difference. For each rod, we can add it to either group or skip it.

Approach

  1. Use a hash map dp where dp[diff] is the maximum sum for the difference diff between two groups.
  2. For each rod, update the map by considering:
    • Adding the rod to the left group (increase diff).
    • Adding the rod to the right group (decrease diff).
    • Skipping the rod (diff unchanged).
  3. After processing all rods, dp[0] is the answer (maximum sum for equal height).

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    int tallestBillboard(vector<int>& rods) {
        unordered_map<int, int> dp;
        dp[0] = 0;
        for (int r : rods) {
            auto cur = dp;
            for (auto& [d, h] : cur) {
                dp[d + r] = max(dp[d + r], h);
                dp[d - r] = max(dp[d - r], h + r);
            }
        }
        return dp[0];
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func tallestBillboard(rods []int) int {
    dp := map[int]int{0: 0}
    for _, r := range rods {
        cur := make(map[int]int)
        for k, v := range dp {
            cur[k] = v
        }
        for d, h := range cur {
            if dp[d+r] < h {
                dp[d+r] = h
            }
            if dp[d-r] < h+r {
                dp[d-r] = h+r
            }
        }
    }
    return dp[0]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
    public int tallestBillboard(int[] rods) {
        Map<Integer, Integer> dp = new HashMap<>();
        dp.put(0, 0);
        for (int r : rods) {
            Map<Integer, Integer> cur = new HashMap<>(dp);
            for (Map.Entry<Integer, Integer> e : cur.entrySet()) {
                int d = e.getKey(), h = e.getValue();
                dp.put(d + r, Math.max(dp.getOrDefault(d + r, 0), h));
                dp.put(d - r, Math.max(dp.getOrDefault(d - r, 0), h + r));
            }
        }
        return dp.getOrDefault(0, 0);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
    fun tallestBillboard(rods: IntArray): Int {
        val dp = mutableMapOf(0 to 0)
        for (r in rods) {
            val cur = dp.toMap()
            for ((d, h) in cur) {
                dp[d + r] = maxOf(dp.getOrDefault(d + r, 0), h)
                dp[d - r] = maxOf(dp.getOrDefault(d - r, 0), h + r)
            }
        }
        return dp[0] ?: 0
    }
}
1
2
3
4
5
6
7
8
def tallestBillboard(rods: list[int]) -> int:
    dp = {0: 0}
    for r in rods:
        cur = dp.copy()
        for d, h in cur.items():
            dp[d + r] = max(dp.get(d + r, 0), h)
            dp[d - r] = max(dp.get(d - r, 0), h + r)
    return dp.get(0, 0)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
use std::collections::HashMap;
impl Solution {
    pub fn tallest_billboard(rods: Vec<i32>) -> i32 {
        let mut dp = HashMap::new();
        dp.insert(0, 0);
        for r in rods {
            let cur = dp.clone();
            for (&d, &h) in &cur {
                dp.insert(d + r, dp.get(&(d + r)).copied().unwrap_or(0).max(h));
                dp.insert(d - r, dp.get(&(d - r)).copied().unwrap_or(0).max(h + r));
            }
        }
        *dp.get(&0).unwrap_or(&0)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
    tallestBillboard(rods: number[]): number {
        let dp = new Map<number, number>();
        dp.set(0, 0);
        for (const r of rods) {
            const cur = new Map(dp);
            for (const [d, h] of cur.entries()) {
                dp.set(d + r, Math.max(dp.get(d + r) ?? 0, h));
                dp.set(d - r, Math.max(dp.get(d - r) ?? 0, h + r));
            }
        }
        return dp.get(0) ?? 0;
    }
}

Complexity

  • ⏰ Time complexity: O(n*S), where n is the number of rods and S is the sum of rods (state space).
  • 🧺 Space complexity: O(S), for the DP map.