class Solution:
def tallestBillboard(self, rods):
dp = {0: 0}
for rod in rods:
cur = dp.copy()
for diff, taller in cur.items():
# Put rod on taller side
dp[diff + rod] = max(dp.get(diff + rod, 0), taller)
# Put rod on shorter side
new_diff = abs(diff - rod)
new_taller = taller + min(rod, diff)
dp[new_diff] = max(dp.get(new_diff, 0), new_taller)
return dp[0]
class Solution {
public:
int tallestBillboard(vector<int>& rods) {
unordered_map<int, int> dp;
dp[0] = 0;
for (int rod : rods) {
auto cur = dp;
for (auto [diff, taller] : cur) {
dp[diff + rod] = max(dp[diff + rod], taller);
int new_diff = abs(diff - rod);
int new_taller = taller + min(rod, diff);
dp[new_diff] = max(dp[new_diff], new_taller);
}
}
return dp[0];
}
};
class Solution {
public int tallestBillboard(int[] rods) {
Map<Integer, Integer> dp = new HashMap<>();
dp.put(0, 0);
for (int rod : rods) {
Map<Integer, Integer> cur = new HashMap<>(dp);
for (Map.Entry<Integer, Integer> entry : cur.entrySet()) {
int diff = entry.getKey(), taller = entry.getValue();
dp.put(diff + rod, Math.max(dp.getOrDefault(diff + rod, 0), taller));
int new_diff = Math.abs(diff - rod);
int new_taller = taller + Math.min(rod, diff);
dp.put(new_diff, Math.max(dp.getOrDefault(new_diff, 0), new_taller));
}
}
return dp.getOrDefault(0, 0);
}
}
var tallestBillboard = function(rods) {
let dp = {0: 0};
for (let rod of rods) {
let cur = {...dp};
for (let diff in cur) {
diff = parseInt(diff);
let taller = cur[diff];
// Put rod on taller side
dp[diff + rod] = Math.max(dp[diff + rod] || 0, taller);
// Put rod on shorter side
let new_diff = Math.abs(diff - rod);
let new_taller = taller + Math.min(rod, diff);
dp[new_diff] = Math.max(dp[new_diff] || 0, new_taller);
}
}
return dp[0] || 0;
};
You are given an array of positive integers called rods
, where each element represents the length of a rod. Your task is to build two supports (billboards) of equal height using some (possibly all) rods. Each rod can be used in only one support or not used at all. You must maximize the height of these two equal supports. If it is not possible to build two supports of the same height, return 0.
0
.At first glance, the problem looks similar to partitioning an array into two subsets of equal sum. However, here we are allowed to leave out some rods, not use all rods, and we want to maximize the equal sum. A brute-force approach would be to try all possible assignments of rods to the two supports or to none, but this is exponential and will not work for large inputs.
The key insight is that for each rod, we have three choices:
We use dynamic programming with a hash map to track the possible differences in heights between the two supports and the best achievable height for the shorter support for each difference.
dp
where dp[diff]
is the maximum height of the shorter support when the height difference between the two supports is diff
.
dp[0] = 0
, meaning both supports have height 0.
diff
:
rod
(diff + rod
).
abs(diff - rod)
. The new height of the shorter support increases by the minimum of rod
and diff
.
dp
(implicitly handled).
dp[0]
holds the maximum possible height for two equal supports.
We use a hash map for dp
to efficiently store and update only the relevant states, since the number of possible differences is much smaller than all possible subset combinations.
Let's use the input rods = [1,2,3,6]
.
dp = {0: 0}
1
:
dp[1] = 0
dp[1] = 0
dp = {0: 0, 1: 0}
2
:
diff=0
, add to taller: dp[2] = 0
dp[2] = 0
diff=1
, add to taller: dp[3] = 0
dp[1] = 1
dp = {0: 0, 1: 1, 2: 0, 3: 0}
3
:
diff=0
, add to taller: dp[3] = 0
dp[3] = 0
diff=1
, add to taller: dp[4] = 1
dp[2] = 1
diff=2
, add to taller: dp[5] = 0
dp[1] = 2
diff=3
, add to taller: dp[6] = 0
dp[0] = 3
dp = {0: 3, 1: 2, 2: 1, 3: 0, 4: 1, 5: 0, 6: 0}
6
:
diff=0
, add to taller: dp[6] = 3
dp[6] = 3
diff=1
, add to taller: dp[7] = 2
dp[5] = 2
diff=2
, add to taller: dp[8] = 1
dp[4] = 3
diff=3
, add to taller: dp[9] = 0
dp[3] = 3
diff=4
, add to taller: dp[10] = 1
dp[2] = 5
diff=5
, add to taller: dp[11] = 0
dp[1] = 5
diff=6
, add to taller: dp[12] = 3
dp[0] = 6
dp = {0: 6, 1: 5, 2: 5, 3: 3, 4: 3, 5: 2, 6: 3, 7: 2, 8: 1, 9: 0, 10:1, 11:0, 12:3}
At the end, dp[0] = 6
, meaning the tallest possible billboard has height 6.
Brute-force approach: Each rod has 3 choices (left, right, unused), so the total number of combinations is 3^n
for n
rods. This is exponential and infeasible for large n
.
Optimized DP approach: For each rod, we iterate over the current states in the hash map. The number of possible differences is bounded by the sum of all rods (call it S
). So, in the worst case, the time and space complexity are O(n*S)
, where n
is the number of rods and S
is the sum of their lengths. However, in practice, the number of states is much smaller due to pruning by the hash map.
The Tallest Billboard problem is a clever twist on subset partitioning. The main insight is to use dynamic programming to track the difference between two supports and the best achievable shorter height for each difference. By updating only the best states and using a hash map, we efficiently explore all combinations without explicit enumeration. This approach balances performance and clarity, making it a powerful technique for similar partitioning and subset problems.