《剑指 Offer (第 2 版)》第 60 题:n 个骰子的点数

第 60 题:n 个骰子的点数(典型动态规划问题)

传送门:AcWing:骰子的点数

将一个骰子投掷 n 次,获得的总点数为 ss 的可能范围为 n ~ 6n

掷出某一点数,可能有多种掷法,例如投掷 2 次,掷出 3 点,共有 [1,2][2,1] 两种掷法。

请求出投掷 n 次,掷出 n ~ 6n 点分别有多少种掷法。

样例1:

输入:n=1

输出:[1, 1, 1, 1, 1, 1]

解释:投掷 1 次,可能出现的点数为 1-6 ,共计 6 种。每种点数都只有 1 种掷法。所以输出 [1, 1, 1, 1, 1, 1]

样例2:

输入:n=2

输出:[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

解释:投掷 2 次,可能出现的点数为 2-12,共计 11 种。每种点数可能掷法数目分别为 1,2,3,4,5,6,5,4,3,2,1。所以输出 [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]

思路:典型动态规划问题。定义状态 dp[i][j] 表示用 i 个骰子扔出和为 j 的可能数,因为第 i 个骰子可能扔出 1-6 的点数。根据此写出状态转移方程:
dp[i][j]=dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j-3]+dp[i-1][j-4]+dp[i-1][j-5]+dp[i-1][j-6]
由于我们只需要用到最后一次的结果,因此为了节省空间可以使用滚动数组,将二维 dp 数组变为一维。

时间复杂度分析:O(n^2)

Python 代码:

class Solution(object):
    def numberOfDice(self, n):
        """
        :type n: int
        :rtype: List[int]
        """
        dp = [0 for _ in range(6 * n + 1)]

        # 动归数组初始值,表示 1 个骰子扔出 1-6 的可能数都为 1
        for i in range(1, 7):
            dp[i] = 1
        # 表示仍第 2 个骰子到第 n 个骰子
        for i in range(2, n + 1):
            # 从后向前写
            for j in range(6 * i, -1, -1):
                dp[j] = 0
                # 最后一个骰子可以扔 1 - 6 点
                for k in range(6, 0, -1):
                    if j - k < 0:
                        continue
                    dp[j] += dp[j - k]
        # 扔 n 个骰子的和为 [n, 6 * n]
        return dp[n:]

作者:cornerCao
链接:https://www.acwing.com/solution/acwing/content/852/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容