LeetCode:956. Tallest Billboard - Python

189 篇文章 3 订阅
151 篇文章 2 订阅
956. 最高的广告牌

问题描述:

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

你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋的长度为123,则可以将它们焊接在一起形成长度为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。

提示:

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

问题分析:

(1)方法一:

把题目的的意思简化一下,其实就是这一组数据分成3组,其中两组的和一样(最大的哦),另外一组无所谓了。不妨给每一个数字打标签分别乘,10-1,总和加起来为0,且,正整数和达到最大(每到一个值,就有三种情况考虑,如下图)
在这里插入图片描述
在实现方面,就可以考虑,深度优先,或者是广度优先+动规来实现。这种方法实现比较简单,但是计算量较大,开辟的空间也大,最坏的情况下为 3 n 3^n 3n 。比较好的是,这个方法仍然可以提交AC的。具体方法有点类似背包问题:

(1)现在设置一个dp,可以python字典表示,k表示,整个序列乘上标签,之后的和,value表示这些序列中正数的和。从上图可以看出来初始化为{0:0}

(2)接下来,就是每处理一个数,就处理一层。简单的理解就是,在上层产生的结果中,如果继续向下分析,在前面的基础上,每个结果有三种可能。

(3)处理的方法为:

            cur = collections.defaultdict(int)
            for s in dp:
                cur[s + i] = max(dp[s] + i, cur[s + i])  # 标记为 1 的情况,并取最大值
                cur[s] = max(dp[s], cur[s])  # 标记为 0 的情况,并取最大值
                cur[s - i] = max(dp[s], cur[s - i])  # 标记为 -1 的情况,并取最大值
            dp = cur  # 更新dp

cur表示当前正在处理的层。dp表示上一层。从这个过程可以看出,其实也是一个动规过程,依赖前面的结果,构成子问题。虽然类似于穷举法,但是在计算过程相同的可能只保留了一个。最后,直接返回dp[0]即可。参考链接在文章下面。

Python3实现:
import collections


class Solution:

    def tallestBillboard(self, rods):
        dp = dict()
        dp[0] = 0  # 初始化dp

        for i in rods:
            cur = collections.defaultdict(int)
            for s in dp:  # 分三种情况考虑
                cur[s + i] = max(dp[s] + i, cur[s + i])
                cur[s] = max(dp[s], cur[s])
                cur[s - i] = max(dp[s], cur[s - i])
            dp = cur
        return dp[0]  # 返回结果


if __name__ == '__main__':
    solu = Solution()
    rods = [1, 2, 3, 4, 5, 6]
    print(solu.tallestBillboard(rods))
(2)方法二:

现在看一下官方的解答,官方的方法是使用递归实现的,其思想采用了深度优先动规 的方法。

(1)令 dp[i][s] 表示使用rods[0:j] (j >= i)时最优解,而s表示,在当前路径中结合3种标签(1,0,-1)的和。

(2)很显然,把每个路径走到头,如果s=0,说明这个路径是可行的,如果不为0,说明此路径是不可行的。

(3)当然,走到头,会有很多种可能,所以选择一个最大的作为结果,即可。

(4)所以,递推公式可以表示为:dp[i][s] = max(dp[i+1][s], dp[i+1][s-rods[i]], rods[i] + dp[i+1][s+rods[i]])

(5)这种思想采用了深度优先 ,感觉也是穷举法

Python3实现:
from functools import lru_cache
class Solution:
    def tallestBillboard(self, rods):
        @lru_cache(None)
        def dp(i, s):
            if i == len(rods):
                return 0 if s == 0 else float('-inf')
            # 三情况取最大
            return max(dp(i + 1, s), dp(i + 1, s - rods[i]), dp(i + 1, s + rods[i]) + rods[i])

        return dp(0, 0)


if __name__ == '__main__':
    solu = Solution()
    rods = [1, 2, 3, 4, 5, 6]
    print(solu.tallestBillboard(rods))

声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。

题目链接 /参考链接1 /参考链接2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值