leetcode 375 原题描述
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
Example:
n = 10, I pick 8. First round: You guess 5, I tell you that it's higher. You pay $5. Second round: You guess 7, I tell you that it's higher. You pay $7. Third round: You guess 9, I tell you that it's lower. You pay $9. Game over. 8 is the number I picked. You end up paying $5 + $7 + $9 = $21.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
是自己一直都不怎么会做的DP问题,看了好几个答案,才有点明白,先记录一下供日后翻看。
参照youtube上一位up主的思路(链接日后附上)。
假设n=5,即在1 2 3 4 5中猜,全局最好的局部最坏情况是什么(是不是很绕口)
一般一开始会想用二分查找,先猜3,再猜1或4,但其实这道题的情景下并不一定这样就能用最少的钱保证一定猜中。所以应该都考虑进去。
具体假设先猜1,2,3,4,5,这就是把所有情况都考虑进去,再对每一中情况取局部最坏情况,用max来表示,保证最终一定会猜中。最终取min(猜1,猜2,猜3,猜4,猜5)。
1:[2 3 4 5]
2: max([1], [3 4 5])
3: max([1 2], [4 5])
4: max([1 2 3], [5])
5: [1 2 3 4]
其实对每个局部的最差又可以进行内层的递归,看起来像是一个树的递归,在数据范围i-j之间用dfs(i,j)来计算,按照up主的高级说法是这样的树dfs问题可以转换为dp[i][j]问题,避免树出栈入栈,减少内存消耗。
dp问题的转移方程是
dp[i][j] = k + max(dp[i][k-1], max(dp[k+1][j]))
其中i-j代表一个子范围,k代表i到j之间的数,如同上面例子中的1,2,3,4,5
具体代码(Python)
class Solution(object):
def getMoneyAmount(self, n):
"""
:type n: int
:rtype: int
"""
dp = [[0]*(n+2) for i in range(n+2)]
for length in range(2, n+1):
for i in range(1, n-length+2):
j = i+length-1
dp[i][j] = float('inf')
for k in range(i, j+1):
dp[i][j] = min(dp[i][j], k+max(dp[i][k-1],dp[k+1][j]))
return dp[1][n]