剑指 Offer 60. n个骰子的点数

题目链接: leetcode.
我:这,,不是个数学题嘛 ,脑子不够,回溯来凑
提交:11 / 11 个通过测试用例 超出时间限制

class Solution {
	vector<int> tmp;
public:
	void dfs(int index, int sum, int n)//该第index个骰子,之前投的和为sum 
	{
		if(index == n)
		{
			tmp[sum]++;//记录本次投的情况 
			return;
		} 
		for(int i = 1;i <= 6;++i)
		{
			dfs(index+1, sum + i, n);
		}
	}
    vector<double> dicesProbability(int n) {
         tmp.resize(n * 6 + 1);
         dfs(0, 0, n);
         vector<double> ans;
         double t = pow(6, n);
		 for(int i = n;i <= 6 * n;++i)
		 {
		 	ans.emplace_back(tmp[i] / t);
		 } 
		 return ans;
    }
};

好的,不是数学题,是动态规划 ┭┮﹏┭┮
dp[i][j]表示i个骰子,投点数之和为j发生的次数
对于第n个骰子,想要投出和为m,投的时候只能投出1-6,所以dp[n][m] = dp[n-1][m-1]+dp[n-1][m-2]+...+dp[n-1][m-6]
初始条件是dp[1][1]dp[1][6]都为1

/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.4 MB, 在所有 C++ 提交中击败了56.95%的用户
*/
class Solution {
public:
    vector<double> dicesProbability(int n) {
         vector<vector<int>> dp(12, vector<int>(67));
         for(int j = 1;j <= 6;++j)
         {
         	dp[1][j] = 1;
         }
         for(int i = 2;i <= n;++i)
         {
         	for(int j = i;j <= 6 * i;++j)
         	{
         		//x表示第i个能投出的点数 
         		for(int x = 1;j - x > 0 && x < 7;++x)
         			dp[i][j] += dp[i-1][j-x];
         	}
         }
         double sum = pow(6, n);
		 vector<double> ans;
		 for(int i = n;i <= 6 * n;++i)
		 {
		 	ans.emplace_back(dp[n][i] / sum);
		 } 
		 return ans;
    }
};

将空间复杂度从(n^2)优化到O(n)

/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.3 MB, 在所有 C++ 提交中击败了65.22%的用户
*/ 
class Solution {
public:
    vector<double> dicesProbability(int n) {
         vector<int> dp(67, 0);
         for(int j = 1;j <= 6;++j)
         {
         	dp[j] = 1;
         }
         for(int i = 2;i <= n;++i)
         {
         	for(int j = 6 * i;j >= i ;--j)//从后往前 
         	{
         		dp[j] = 0;//否则要加上dp[i-2][j-x]啦 
         		//x表示第i个能投出的点数 
         		for(int x = 1;j - x >= i - 1 && x < 7;++x)//边界条件要改变 
         		{
         			dp[j] += dp[j-x];
         		}	
         	}
         }
         double sum = pow(6, n);
		 vector<double> ans;
		 for(int i = n;i <= 6 * n;++i)
		 {
		 	ans.emplace_back(dp[i] / sum);
		 } 
		 return ans;
    }
};

优化的时候最好还是画个图吧,首先从后往前遍历是个技巧,其次遍历的边界条件要考虑好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值