有一些不规则的硬币。在这些硬币中,prob[i] 表示第 i 枚硬币正面朝上的概率。
请对每一枚硬币抛掷 一次,然后返回正面朝上的硬币数等于 target 的概率。
示例 1:
输入:prob = [0.4], target = 1
输出:0.40000
示例 2:
输入:prob = [0.5,0.5,0.5,0.5,0.5], target = 0
输出:0.03125
提示:
1 <= prob.length <= 1000
0 <= prob[i] <= 1
0 <= target <= prob.length
如果答案与标准答案的误差在 10^-5 内,则被视为正确答案。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/toss-strange-coins
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
一道数学题,
可以用DP解,用 dp[ i ][ j ]表示前 i 个硬币里有 j 个硬币正面朝上的概率。
状态转移方程:
if i > 0:
dp[i][j] = dp[i - 1][j] * (1 - p) + dp[i - 1][j - 1] * p
解释:当投完本次硬币之后,目前的i个硬币里有j个硬币正面朝上的概率,
应该等于两种情况的概率之和,
1. 这次投的是背面,前 i - 1 个硬币里有 j 个硬币正面朝上,
2. 这次投的是正面,前 i - 1 个硬币里有 j - 1 个硬币正面朝上。
时间复杂度:O(M * N)
空间复杂度:O(M * N)
class Solution(object):
def probabilityOfHeads(self, prob, target):
"""
:type prob: List[float]
:type target: int
:rtype: float
"""
dp = [[0 for _ in range(len(prob) + 1)] for _ in range(len(prob))]
# dp[i][j] 表示前i个硬币里,有j个硬币正面朝上的概率
dp[0][1] = prob[0]
dp[0][0] = 1 - prob[0]
for i, p in enumerate(prob):
for j in range(target + 1):
if i > 0:
dp[i][j] += dp[i - 1][j] * (1 - p) # 当前硬币正面朝下
dp[i][j] += dp[i - 1][j - 1] * (p) # 当前硬币正面朝上
return dp[-1][target]
第二种思路:
观察一下可以发现二维DP没有必要,因为状态只在相邻的 i 之间发生转化,所以用两个一维数组表示DP即可。
时间复杂度:O(M * N)
空间复杂度:O(M)
class Solution(object):
def probabilityOfHeads(self, prob, target):
"""
:type prob: List[float]
:type target: int
:rtype: float
"""
dp = [0 for _ in range(len(prob) + 1)]
dp[1] = prob[0]
dp[0] = 1 - prob[0]
for i in range(1, len(prob)):
new_dp = [0 for _ in range(len(prob) + 1)]
for j in range(target + 1):
new_dp[j] = dp[j] * (1 - prob[i]) + dp[j - 1] * prob[i]
dp = new_dp[:]
return dp[target]