每日一题 -- leetCode956

204 阅读3分钟

image.png 「这是我参与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

总结

无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。