Leetcode 956:最高的廣告牌(超詳細的解法!!!)
你正在安裝一個廣告牌,並希望它高度最大。這塊廣告牌將有兩個鋼製支架,兩邊各一個。每個鋼支架的高度必須相等。
你有一堆可以焊接在一起的鋼筋 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
解題思路
對於這個問題首先想到的解決思路是通過DFS
。我們遍歷rods
中的元素,我們對每個元素都有如下三種考量。
- 放左邊
- 放右邊
- 不放
當我們左邊鋼筋的長度left
和右邊鋼筋的長度right
是一樣的時候,我們就需要記錄這種情況下的最大值res
。我們在初始的時候需要記錄一個最大容量maxsum
(sum(rods)
i
,我們就要將maxsum
減去相應的值rods[i]
。我們接著思路遞迴到底的情況。
- 遍歷完
rods
的最後一個元素
第一種情況自然不用多說。第二種情況,我們最後無法得到left==right
的情形,所以也要返回。對於第三種情況,我們此時res
就是最大長度了,所以直接返回就可以了。
我們在一開始的時候,也就是放入第一根鋼筋的時候,我們只要考慮放和不放,而不需要考慮放左還是放右。一切安排妥當,我們開始寫程式碼
class Solution:
def tallestBillboard(self, rods):
"""
:type rods: List[int]
:rtype: int
"""
if len(rods) == 0 or len(rods) == 1:
return 0
self.res = 0
rods.sort(reverse=True)# add sort
remain = sum(rods)
self.dfs(rods, remain - rods[0], 0, rods[0], 0)
self.dfs(rods, remain - rods[0], 0, 0, 0)
return self.res
def dfs(self, rods, remain, i, left, right):
if abs(left - right) > remain or\
(left + right + remain <= self.res*2):
return
if left == right and self.res < left:
self.res = left
i += 1
if i == len(rods):
return
remain -= rods[i]
self.dfs(rods, remain, i, left + rods[i], right)
self.dfs(rods, remain, i, left, right + rods[i])
self.dfs(rods, remain, i, left, right)
但是我們這樣做了之後超時了。我們需要一步優化,我們可以在開始的時候對rods
按照從大到小排序(貪心策略)。
這個問題有個巧妙的方法,我們首先定義函式 返回距離差是 的最大公共長度。例如
我們此時知道兩者長度相差
,那麼此時
。此時如果我們新加入一個鋼筋x
,那麼我們有兩種策略,第一種是加在上面
那麼我們知道此時的 。我們也可以將它加入到下面
那麼我們知道此時的 ,或者也可以是下面這種
那麼我們知道此時的 。
但是這樣做有什麼用呢?我們雖然能保證最大的公有長度,但是這個公有長度不一定可以通過所給的rods
中的元素拼湊出來啊?是的,確實是這樣。但是我們可以保證的是
一定可以通過rods
中的元素拼湊出來,而
恰好就是我們所需要的結果,非常好的思路。
class Solution:
def tallestBillboard(self, rods):
"""
:type rods: List[int]
:rtype: int
"""
mem = {0: 0}
for i in rods:
cur = mem.copy()
for d, val in cur.items():
mem[d + i] = max(mem.get(i + d, 0), val)
mem[abs(d - i)] = max(mem.get(abs(d - i), 0), val + min(i, d))
return mem[0]
reference:
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!