剑指60 n个骰子的点数
把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。
你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。
可以把问题分解成n-1个和1个骰子,加上这个骰子后,对于可能出现的点数x。他的值等于(x-1)+(x-2)+..+(x-6)这六个值的和,所以这也是一个递归思路的问题,但是也有很多重复计算,所以自底向上使用循环。
用两个数组分别记录上一次结果和这一次结果,每次交换。初始第一个数组需要初始1-6为1,然后每次循环时,假如是使用x个骰子,那么0-x-1就要初始化为0。
1 class Solution { 2 public: 3 int maxValue=6; 4 vector<double> twoSum(int n) { 5 vector<double> ratio; 6 int *probabilities[2]; 7 probabilities[0]=new int[maxValue*n+1]; 8 probabilities[1]=new int[maxValue*n+1]; 9 for(int i=0;i<maxValue*n+1;++i){ 10 probabilities[0][i]=0; 11 probabilities[1][i]=0; 12 } 13 int flag=0; 14 for(int i=1;i<=maxValue;++i){ 15 probabilities[flag][i]=1; 16 } 17 for(int num=2;num<=n;++num){ 18 for(int i=0;i<num;++i) 19 probabilities[1-flag][i]=0; 20 21 for(int i=num;i<=maxValue*num;++i){ 22 probabilities[1-flag][i]=0; 23 for(int j=1;j<=i && j<=maxValue;++j){ 24 probabilities[1-flag][i]+=probabilities[flag][i-j]; 25 } 26 } 27 flag=1-flag; 28 } 29 double total=pow((double)maxValue,n); 30 for(int i=n;i<=maxValue*n;++i){ 31 ratio.push_back(probabilities[flag][i]/total); 32 } 33 return ratio; 34 } 35 };
注意for循环中++i和i++都是效果一样的,因为for循环是在执行循环体后才执行for语句中最后一项。但是也有微小区别,i++需要申请一个空间临时存放i,然后返回计算的值;++i可以直接在原空间上执行,所以++i速度会更快。