Leetcode 956:最高的广告牌

你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。

你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为 1、2 和 3,则可以将它们焊接在一起形成长度为 6 的支架。

返回广告牌的最大可能安装高度。如果没法安装广告牌,请返回 0。

示例 1:

输入:[1,2,3,6]
输出:6
解释:我们有两个不相交的子集 {1,2,3} 和 {6},它们具有相同的和 sum = 6。
1
2
3
示例 2:

输入:[1,2,3,4,5,6]
输出:10
解释:我们有两个不相交的子集 {2,3,5} 和 {4,6},它们具有相同的和 sum = 10。
1
2
3
示例 3:

输入:[1,2]
输出:0
解释:没法安装广告牌,所以返回 0。
1
2
3
提示:

0 <= rods.length <= 20
1 <= rods[i] <= 1000
钢筋的长度总和最多为 5000

思路:

一开始一直都不懂,思路的话,最开始暴力,每一个都有不放,放在左边,放在右边三种,复杂度0(n的三次方)

之后还可以用dfs,dfs中去维护一个最大值,但是这样的话还是每个都有三种情况,复杂度不会有什么变化,包括每一个去赋值每一个打上1 ,-1,0的标签,下来都是一样的,所以,动归该怎么做呢?

思路还是挺神的,因为他存的东西比较难想

那定义 dp[i][j] 来表示 前 i 个支架高度差为 j 的时候,最长的公共长度。,这么的话出口就是j为0的时候了,然后去维护一个最大的dp的值就ok了

然后列出三种状态转移式

  1. 支架不添加到任何一端 :
    这种情况下的 dp[i][j] = dp[i-1][j] 因为第 i 个不用,所以它的最优的公共长度应该 = max( dp[i-1][j], dp[i][j] )
  2. 支架添加到高的一端
    这种情况下即,高的更高, dp[i][j+h] = max(dp[i][j+h] , dp[i][j] + h) //这里不懂哎,为啥会是dp【i】【j】+h?

  3. 支架添加到短的一端

这种情况则是把新加进来的支架加到短的一端,也就是加长了短一端的长度,这个时候还会有两种情况,要么是短的加了一截还是短,另一种是短的加了一截变长了。把这两种情况合并一下:即
dp[i][|j-h|] = max( dp[i][|j-h|] , dp[i-1][j] + min(j, h) )

class Solution {
    public int tallestBillboard(int[] rods) {
        int len = rods.length;
        int[][] dp = new int[len+1][5001];
        for (int i = 0; i < len+1; i++)
            for (int j = 0; j < dp[0].length; j++) dp[i][j] = -5001;
        int sum = 0;
        dp[0][0] = 0;
        for (int i = 1; i <= len; i++) {
            sum += rods[i-1];
            for (int j = 0; j <= sum; j++) {
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j]);
                if (j + rods[i-1] <= sum)
                    dp[i][j+rods[i-1]] = Math.max(dp[i-1][j], dp[i][j+rods[i-1]]);

                dp[i][Math.abs(j-rods[i-1])] = Math.max(dp[i][Math.abs(j-rods[i-1])], dp[i-1][j] + Math.min(j,rods[i-1]));
            }
        }
        return dp[len][0];
    }
}

这道题就是没有很懂啊,

参考:https://blog.csdn.net/qq_17550379/article/details/85070792

https://blog.csdn.net/qq_38595487/article/details/85064300

你可能感兴趣的:(算法dp)