题目:扔 n 个骰子,向上面的数字之和为 S。给定 Given n,请列出所有可能的 S 值及其相应的概率。
一开始的想法是:
投n个骰子,其实就是n次1-6的循环,将其每次和放在一个列表中,后面根据数字之和S范围(n,6n),用list.count(s[i])求出来每个情况下的次数之和,但是这样的话会导致内存超出限制,1-15个骰子还能够实现,后面基本不能。
一开始代码如下:
def sum1(x):
count1=[]
for i in x:
for j in range(1,6+1):
z=i+j
count1.append(z)
return count1
def dicesSum(self, n):
# Write your code here
if n==0 :
return None
if n==1:
yy=[[1, 0.17], [2, 0.17], [3, 0.17], [4, 0.17], [5, 0.17], [6, 0.17]];
return yy
mylist=[1,2,3,4,5,6]
for k in range(1,n):
mylist=sum1(mylist);
x=[]
z1 = float(6**n)
for z in range(n,6*n+1):
result=mylist.count(z)
x=x+[[z,result/z1]]
return mylist
后面,找到网上一篇python这道题的代码,它通过动态规划,第一次开始累加到第n次骰子,其中发现到规律,n个骰子有5*n+1种s结果(6n-n+1),他们是对称情况,如果结果是偶数,则中间(5*n+1)/2和(5*n+1)/2+1是相同。
代码如下:
def dicesSum(self, n):
# Write your code here
if n == 0 : return None
result = [
[1,1,1,1,1,1],
] #一开始第一个骰子出现的情况
# if n == 1: return result[0]
# 计算n个骰子出现的各个次数和
for i in range(1,n):
x = 5*(i+1)+1 #骰子从第二个开始出现取值可能的次数的情况有5n+1,这里n=i+1
result.append([0 for _ in range(x)]) #重新一列后面补为0
for j in range(x):
if j < 6: #前六
result[i][j] = (sum(result[i-1][0:j+1]))
elif j >=6 and j <= 3*i+2: #六
result[i][j] = (sum(result[i-1][j-5:j+1]))#前面的n-1,
else:
break
left = 0
right = len(result[i]) - 1
while left <= right:
result[i][right] = result[i][left]
left += 1
right -= 1 #他们呈现对称
res = result[-1] #列表的倒数第一列
all = float(sum(res))
other = []
# 第i个元素代表骰子总和为n+i
for i,item in enumerate(res): #额numerate遍历序列中的元素以及它们的下标
# pro = self.round(item/all)
# 自己写的四舍五入算法和LintCode有出入,其实网站自身会处理数据,这里不再做处理
pro = item/all
other.append([n+i,pro])
return other
总结:
要考虑到内存和时间的限制
学会逆向思考,找到规律。