「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」
前言
每日一题,轻松解题
每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。
正文
:最高的广告牌
难度:困难
题目要求:
你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。
你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为 1、2 和 3,则可以将它们焊接在一起形成长度为 6 的支架。
返回 广告牌的最大可能安装高度 。如果没法安装广告牌,请返回 0 。
分析题目:
实际理解就是给一堆管子,搭配出两根最长并且长度相等的管子,
代码理解就是给一个整数数组,在这些元素中找到两个子数组的元素和相等并且最大的情况,
ps:可以有元素不被使用,但必须最长且相等
举个例子
输入: [1,2,3,4,5,6]
输出: 10
解释: 我们有两个不相交的子集 {2,3,5} 和 {4,6},它们具有相同的和 sum = 10。
:解题
理清思路:
暴力搜索的复杂度可以用“折半搜索”优化。在这个问题中,我们有 3^N3 N 种可行方案,对于每个钢筋 x 可以考虑 +x,-x,或者 0 ,我们要让暴力的速度更快。
我们可以让前 3^{N/2}3 N/2 和后一半分开来考虑,然后再合并他们。例如,如果有钢筋 [1, 3, 5, 7],那么前两根钢筋可以构成九种状态:[0+0, 0+3, 0-3, 1+0, 1+3, 1-3, -1+0, -1+3, -1-3],后两根钢筋也可以构成九种状态。
我们对每个状态记录正数之和,以及负数绝对值之和。例如,+1 +2 -3 -4 记为 (3, 7)。同时记状态的 delta 为两者之差 3-7,所以这个状态的 delta 为 -4。
我们的目标是将两个状态合并,使得 delta 之和为 0。score 是所有正数之和,我们希望获得最高的 score。对于每个 delta 我们只会记录具有最高 score 的状态。
分析:
将钢筋分成左右两半:左侧和右侧。
对于每一半,暴力计算可达的所有状态,如上定义。然后针对所有状态,记录下 delta 和最大的 score。
然后我们有左右两半的 [(delta, score)] 信息。我们找到 delta 为 0 时最大的 score 和。
编辑代码:
class Solution(object):
def tallestBillboard(self, rods):
def make(A):
states = {(0, 0)}
for x in A:
states |= ({(a+x, b) for a, b in states} |
{(a, b+x) for a, b in states})
delta = {}
for a, b in states:
delta[a-b] = max(delta.get(a-b, 0), a)
return delta
N = len(rods)
Ldelta = make(rods[:N/2])
Rdelta = make(rods[N/2:])
ans = 0
for d in Ldelta:
if -d in Rdelta:
ans = max(ans, Ldelta[d] + Rdelta[-d])
return ans
总结
无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。