375 猜数字大小 II(区间dp)

1. 问题描述:
我们正在玩一个猜数游戏,游戏规则如下:
我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字。
每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了。
然而,当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。直到你猜到我选的数字,你才算赢得了这个游戏。
n = 10, 我选择了8.
第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。
第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。
第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。
游戏结束。8 就是我选的数字。
你最终要支付 5 + 7 + 9 = 21 块钱。
给定 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/

2. 思路分析:

分析题目可以知道系统给出的数字位于区间[1, n]中,当我们猜一个数字的时候判断与系统给出的数字的大小关系那么就可以判断出系统给出的数字是左边还是右边,因为涉及到区间的问题所以我们考虑使用区间dp的思路解决,在区间[1, n]中所有可能目标值下尝试所有可能猜法,例如第一次的时候可以猜1,2,3,...n,当我们第一次猜某一个数字的时候那么判断当前猜的数字与系统数字的关系判断系统的数字是左边还是右边,接下来就猜确定的一边的数字即可,我们的目标是在所有可能猜的目标值的最坏情况下花费的最少金额(当前数字左右两边最坏的情况,系统生成的数字可能在左边也可能在右边)。可以声明一个长度为n + 2的二维数组或者列表,长度为n + 2表示我们可以猜第一个数字与最后一个数字对应的状态,dp[i][j]表示区间[i, j]所有目标值对应的所有猜法下最坏情况下花费的最少金额,可以从长度为2的区间开始一直递推到长度为n的区间,对于区间[i, j]我们可以尝试猜所有可能数字下最坏情况下花费的最少金额即可,也即对于长度为l的区间[i, j],枚举区间的每一个分界点k,表示当前在[i, j]区间中猜的数字是k,我们需要计算min(dp[i][j], max(dp[i][k - 1], dp[k + 1][j]) + k)即可,左右两边取一个最大值表示系统生成的数字可能在左边也可能在右边(若k就是目标值肯定不是最坏的情况不用管),我们需要在这两种情况下取一个max表示猜k的时候最坏情况下的金额,再取一个min表示区间[i, j]最坏情况下花费的最少金额。

3. 代码如下:

import sys
class Solution:
    # 典型的区间dp问题
    def getMoneyAmount(self, n: int) -> int:
        dp = [[0] * (n + 2) for i in range(n + 2)]
        for l in range(2, n + 1):
            i = 1
            while i + l - 1 <= n:
                j = i + l - 1
                dp[i][j] = sys.maxsize
                for k in range(i, j + 1):
                    dp[i][j] = min(dp[i][j], max(dp[i][k - 1], dp[k + 1][j]) + k)
                i += 1
        return dp[1][n]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值