[算法][動態規劃][騰訊面試手撕題]拋硬幣問題

① 題目描述

有一些不規則的硬幣。在這些硬幣中,pi1p_{i-1}表示第ii枚硬幣正面朝上的概率(ii從1起)。
請對每一枚硬幣拋擲一次,然後返回正面朝上的硬幣數等於targettarget的概率。

② 問題求解

誤區:這題容易被排列組合的想法先入爲主,其實這是一個動態規劃的問題。

1 動態方程

dp[i][j]dp[i][j]爲拋第ii個硬幣時恰好有jj個朝上的概率,則:

dp[i][j]=dp[i1][j](1pi1)+dp[i1][j1]pidp[i][j]=dp[i-1][j]*(1-p_{i-1}) +dp[i-1][j-1]*p_i

反向迭代可以去除ii的維度,將空間優化爲:

dp[j]=dp[j](1pi1)+dp[j1]pidp[j]=dp[j]*(1-p_{i-1}) +dp[j-1]*p_i

其中,dp[j]dp[j]爲恰有jj個硬幣朝上的概率。

2 代碼求解

"""
思路:
    動態規劃 res[x]指的是恰好x個爲正的概率
    @See 動態規劃 https://leetcode-cn.com/tag/dynamic-programming/
樣例輸入:
    prob = [0.4], target = 1
    prob = [0.5,0.5,0.5,0.5,0.5], target = 0
樣例輸出:
    0.4000
    0.03125
"""
from typing import List


class Solution:
    def cal_probability(self, prob: List[float], target: int) -> float:
        res = [0 for _ in range(len(prob) + 1)]
        res[0] = 1.0
        for i in range(1, len(prob)+1):
            for j in range(min(i, target), -1, -1):
                # 恰好j個爲正 = 上一輪更新中j個正面的情況下第i個恰好爲反 + 已經j-1個正面的情況下第i個繼續爲正
                res[j] = (res[j] * (1 - prob[i - 1])) + ((res[j - 1] * prob[i - 1]) if j > 0 else 0)

        return res[target]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章