LintCode——筛子求和
描述:扔n个骰子,向上面的数字之和为 S 。给定 Given n,请列出所有可能的 S 值及其相应的概率。
样例:给定n=1,返回 [ [1, 0.17], [2, 0.17], [3, 0.17], [4, 0.17], [5, 0.17], [6, 0.17]]
解题思路:假定有n个骰子,那么可投掷出的数字在n~6n之间,即S的取指在n~6n之间,n个骰子投掷会出现6的n次方种情况;我们采用递归思想,求n个骰子投出num的情况数的时,需要递归求n-1个骰子投出num-1,num-2,num-3...num-6的情况,而求n-1个骰子投出num-1的情况数的时候,需要递归求n-2个骰子投出num-2,num-3,num-4...,num-12的情况;依次类推,其中会有重复求解的过程,为了优化算法,我们采用动态规划技术来减少不必要的重复求解过程。使用HashMap<string,double>来存储已经计算好的情况数。这里String作为键,用以标记“x个骰子投出y”,值Double为情况数。
1 public class Solution { 2 /** 3 * @param n an integer 4 * @return a list of Map.Entry<sum, probability> 5 */ 6 public List<Map.Entry<Integer, Double>> dicesSum(int n) { 7 // Write your code here 8 // Ps. new AbstractMap.SimpleEntry<Integer, Double>(sum, pro) 9 // to create the pair 10 List<Map.Entry<Integer, Double>> list = new ArrayList<Map.Entry<Integer,Double>>(5 * n + 1); 11 Double pro = 0.0; 12 double total = Math.pow(6, n); 13 double conditions = 0; 14 HashMap<String,Double> hashMap = new HashMap<>(); 15 for(int i = n;i <= 6 * n;i++){ 16 pro = 0.0; 17 conditions = findCombs(i, n,hashMap); 18 pro = conditions / total; 19 list.add(new AbstractMap.SimpleEntry<Integer, Double>(i,pro)); 20 } 21 return list; 22 } 23 24 public static double findCombs(int num,int n,HashMap<String, Double>hashMap){ 25 //为了简化计算,假设每个骰子最小值为0,最大值为5,共n个骰子 26 double total = 0; 27 String key = String.valueOf(num) + "," + String.valueOf(n); 28 if(hashMap.containsKey(key)){//若前面已经计算过该状态则直接返回结果 29 return hashMap.get(key); 30 } 31 32 if(num <= 0){ 33 if(n >= 1) 34 total = 0; 35 else 36 total = 1;//0 个骰子得到0 是可以的 37 } 38 else{ 39 //num >0 40 if(n < 1){ 41 total = 0; 42 } 43 else if(n == 1){ 44 if(num > 6) 45 total = 0; 46 else 47 total = 1; 48 } 49 else{ 50 int ceil = num <= 6 ? num : 6; 51 for(int i = 1;i <= ceil;i++){ 52 total += findCombs(num-i, n-1,hashMap); 53 } 54 } 55 } 56 hashMap.put(key, total); 57 return total; 58 } 59 }