你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。
你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为 1、2 和 3,则可以将它们焊接在一起形成长度为 6 的支架。
返回广告牌的最大可能安装高度。如果没法安装广告牌,请返回 0。
示例 1:
输入:[1,2,3,6]
输出:6
解释:我们有两个不相交的子集 {1,2,3} 和 {6},它们具有相同的和 sum = 6。
示例 2:
输入:[1,2,3,4,5,6]
输出:10
解释:我们有两个不相交的子集 {2,3,5} 和 {4,6},它们具有相同的和 sum = 10。
示例 3:
输入:[1,2]
输出:0
解释:没法安装广告牌,所以返回 0。
提示:
0 <= rods.length <= 20
1 <= rods[i] <= 1000
钢筋的长度总和最多为 5000
思路:一个比较直观的方法是折半搜索,我们可以将原数组分成两部分分别进行枚举,其中每个元素有三种状态(第一个广告牌取,第二个广告牌取,两个都不取),复杂度只有O(3^(20/2))。鉴于这种方法比较简单,我这里不再赘述,我更倾向于放出复杂度更优的代码。
我们考虑动态规划,定义dp[i][j]表示前i个钢筋使得两个广告牌高度差为j的最大和,而我们最终要找的就是dp[n][0]/2的值。
class Solution {
public int tallestBillboard(int[] rods) {
int sum=0;
int n=rods.length;
for(int i=0;i<rods.length;i++)
sum+=rods[i];
int[][] dp=new int[n+1][2*sum+1];
for(int i=1;i<=n;i++)
for(int j=0;j<=sum;j++) {
if(dp[i-1][j]<j)
continue;
int val=j+rods[i-1];
dp[i][val]=Math.max(dp[i][val], Math.max(dp[i-1][val], dp[i-1][j]+rods[i-1]));
val=Math.abs(j-rods[i-1]);
dp[i][val]=Math.max(dp[i][val], Math.max(dp[i-1][val], dp[i-1][j]+rods[i-1]));
dp[i][j]=Math.max(dp[i][j], dp[i-1][j]);
}
return dp[n][0]/2;
}
}