《剑指offer》60--n 个骰子的点数[C++]

NowCoder

题目描述

把 n 个骰子扔在地上,求点数和为 s 的概率。

解题思路

1 递归大法

重复计算,计算复杂度大。

2 循环大法

a 动态规划

空间复杂度:O(N^2)

使用一个二维数组 dp 存储点数出现的次数,其中 dp[i][j] 表示前 i 个骰子产生点数 j 的次数。

class Solution {
public:
    /**
     * @param n an integer
     * @return a list of pair
     */
    vector> dicesSum(int n) {
        const int face = 6;
        const int pointNum = face*n;
        vector< vector > dp(n+1, vector(pointNum+1));
        for(int i=1; i<=face; ++i)  dp[1][i] = 1;
        for(int i=2; i<=n; ++i)
            for(int j=i; j<=pointNum; ++j) /* 使用 i 个骰子最小点数为 i */
                for(int k=1; k<=face && k<=j; ++k)
                    dp[i][j] += dp[i-1][j-k];
        const double totalNum = pow(6, n);
        vector> res;
        for(int i=n; i<= pointNum; ++i) res.push_back(make_pair(i, dp[n][i]/totalNum));
        return res;
    }
};

动态规划+旋转数组

空间复杂度:O(N)

class Solution {
public:
    vector> dicesSum(int n) {
        const int face = 6;
        const int pointNum = face*n;
        vector< vector > dp(2, vector(pointNum+1));
        for(int i=1; i<=face; ++i)  {
            dp[0][i] = 1;
        }
        int flag = 1; /* 旋转标记 */
        for (int i=2; i<=n; i++, flag=1-flag) {
            for (int j=0; j<=pointNum; j++) dp[flag][j] = 0; /* 旋转数组清零 */
            for (int j=i; j<=pointNum; j++)
                for (int k=1; k<=face && k<=j; k++)
                    dp[flag][j] += dp[1-flag][j-k];
        }
        const double totalNum = pow(6, n);
        vector> res;
        for(int i=n; i<= pointNum; ++i) res.push_back(make_pair(i, dp[1-flag][i]/totalNum));
        return res;
    }
};

 

你可能感兴趣的:(剑指offer)