No.837 LeetCode題目 “新21點”

題目描述

愛麗絲參與一個大致基於紙牌遊戲 “21點” 規則的遊戲,描述如下:

愛麗絲以0分開始,並在她的得分少於 K分時抽取數字。 抽取時,她從[1, W]的範圍中隨機獲得一個整數作爲分數進行累計,其中W 是整數。 每次抽取都是獨立的,其結果具有相同的概率。

當愛麗絲獲得不少於K分時,她就停止抽取數字。 愛麗絲的分數不超過N 的概率是多少?

示例 1:

輸入:N = 10, K = 1, W = 10
輸出:1.00000
說明:愛麗絲得到一張卡,然後停止。

示例 2:

輸入:N = 6, K = 1, W = 10
輸出:0.60000
說明:愛麗絲得到一張卡,然後停止。
在 W = 10 的 6 種可能下,她的得分不超過 N = 6 分。

示例 3:

輸入:N = 21, K = 17, W = 10
輸出:0.73278

提示:

0 <= K <= N <= 10000
1 <= W <= 10000
如果答案與正確答案的誤差不超過 10^-5,則該答案將被視爲正確答案通過。
此問題的判斷限制時間已經減少。

解題思路

本題利用動態規劃的思想,令dp[i]表示當手裏的數字爲i時獲勝的概率,本題要求dp[0]
因爲手中牌最大爲K+W-1(手中牌爲K-1,又抽中了W),因此初始化一個長度爲K+W的數組。

  • 當手中的牌當N >= i >= K時,遊戲結束,獲得勝利(返回1)。當i>N時,遊戲失敗(返回0)。
  • 當手中的牌i <= K-1時,dp[i] = (dp[i+1]+...+dp[i+W]) / W

由於利用循環求和dp[i+1]+...+dp[i+W]時會超出時間限制,因此我們利用窗口效應,設一個變量window來記錄當前的dp[i+1]+...+dp[i+W]i每向前移動一格,窗口也會跟着移動一格。如下圖所示:
在這裏插入圖片描述
上圖參考:
https://leetcode-cn.com/problems/new-21-game/solution/

具體實現細節詳見僞代碼。

完整代碼

class Solution {
public:
    double new21Game(int N, int K, int W) {
      //如果K爲0,最後肯定可以成功。
      if(K == 0){
        return 1.0;
      }
      //利用動態規劃的思想,dp[i]表示當手裏的數字爲i時獲勝的概率,本題要求dp[0]。
      //手中牌最大爲K+W-1,因此初始化一個長度爲K+W的數組。
      double dp[K+W];
      /*for(int i =0;i<K+W-1;i++){
        dp[i] = 0;
      }*/
      double window = 0.0;
      //當N>=i>=K時,遊戲結束,獲得勝利。當i>N時,遊戲失敗。
      for(int i = K;i<K+W;i++){
        dp[i] = (i > N) ? 0 : 1.0;
        window += dp[i];//利用window值記錄這一總和(滑動窗口原理)
      }
      //當i<=K-1時,dp[i] = (dp[i+1]+...+dp[i+W])/W
      for(int i = K-1;i>=0;i--){
        dp[i] = window/W;
        window += dp[i];
        window -= dp[i+W];
      }
      return dp[0];
    }
};

性能結果

在這裏插入圖片描述

個人感悟

做了一些動態規劃的題,個人感覺確實是狀態轉移方程最難寫。
有些時候需要求dp[i],比如No.194 LeetCode題目 “打家劫舍”
有些時候需要求dp[0],比如本題。

這兩種思路主要是要考慮從前往後計算,還是從後往前計算。
這道題就是要從後往前計算,因爲後一狀態決定了前一狀態。

同時dp[i]這個物理量如何解釋也是要思考的問題之一,之後遇到動態規劃還要多多練習。

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