1. 程式人生 > >n個骰子的點數(Java實現)

n個骰子的點數(Java實現)

本題為劍指offer面試題43

沒有找到牛客網的測試例題

題目:把n個骰子仍在地上,所有骰子朝上一面的點數之和為s,輸入n,打印出s的所有可能的值出現的概率。

解法一:基於遞迴求骰子的點數,時間效率不夠高

現在我們考慮如何統計每一個點數出現的次數。要向求出n個骰子的點數和,可以先把n個骰子分為兩堆:第一堆只有一個,另一個有n-1個。單獨的那一個有可能出現從1到6的點數。我們需要計算從1到6的每一種點數和剩下的n-1個骰子來計算點數和。接下來把剩下的n-1個骰子還是分成兩堆,第一堆只有一個,第二堆有n-2個。我們把上一輪哪個單獨骰子的點數和這一輪單獨骰子的點數相加,再和n-2個骰子來計算點數和。分析到這裡,我們不難發現這是一種遞迴的思路,遞迴結束的條件就是最後只剩下一個骰子。

解法二:基於迴圈求骰子的點數,時間效能好

可以換一個思路來解決這個問題,我們可以考慮用兩個陣列來儲存骰子點數的每一個綜述出現的次數。在一次迴圈中,每一個數組中的第n個數字表示骰子和為n出現的次數。在下一輪迴圈中,我們加上一個新的骰子,此時和為n出現的次數。下一輪中,我們加上一個新的骰子,此時和為n的骰子出現的次數應該等於上一次迴圈中骰子點數和為n-1,n-2,n-3,n-4,n-5,n-6的次數之和,所以我們把另一個數組的第n個數字設為前一個數組對應的第n-1,n-2,n-3,n-4,n-5,n-6 


Java程式碼如下:

package go.jacob.day516;

import java.text.DecimalFormat;

/*
 * 劍指offer面試題43:n個骰子的點數
 */
public class Demo1 {
	public static void main(String[] args) {
		printProbability_1(12);
		printProbability_2(12);
	}

	// 骰子最大點數
	static int g_maxValue = 6;

	/*
	 * 方法一:基於遞迴實現 
	 * 缺點:時間複雜度過高
	 */
	public static void printProbability_1(int number) {
		long start = System.currentTimeMillis();
		if (number < 1)
			return;
		int maxSum = number * g_maxValue;
		// probabilities陣列用來儲存每個sum出現的次數,範圍是從number到maxSum
		int[] probabilities = new int[maxSum - number + 1];
		// 陣列初始化
		for (int i = 0; i < maxSum - number + 1; i++) {
			probabilities[i] = 0;
		}

		probability(number, probabilities);
		double total = Math.pow((double) g_maxValue, (double) number);
		// 打印出從number到maxSum每個數字出現的概率
		DecimalFormat df = new DecimalFormat("0.000");
		System.out.print("遞迴實現:");
		for (int i = 0; i < maxSum - number + 1; i++) {
			System.out.print(df.format(probabilities[i] / total) + " ");
		}
		System.out.println();
		long end = System.currentTimeMillis();
		long result = end - start;
		System.out.println("執行時間:" + result);

	}

	private static void probability(int number, int[] probabilities) {
		for (int i = 1; i <= g_maxValue; i++)
			probability(number, number - 1, i, probabilities);

	}

	// current表示當前處理的是第幾個骰子
	private static void probability(int number, int current, int sum, int[] probabilities) {
		// 當current==0,說明所有的骰子處理結束,遞迴結束
		if (current == 0) {
			probabilities[sum - number]++;
			return;
		}
		for (int i = 1; i <= g_maxValue; i++) {
			probability(number, current - 1, sum + i, probabilities);
		}
	}

	/*
	 * 方法2:迴圈實現 f(n)=f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)+f(n-6) 時間複雜度低
	 */
	public static void printProbability_2(int number) {
		long start = System.currentTimeMillis();
		if (number < 1)
			return;
		int maxSum = number * g_maxValue;
		int[][] probabilities = new int[2][maxSum + 1];
		// 通過falg來迴圈利用陣列
		int flag = 0;
		// 初始化第一個骰子
		for (int i = 1; i <= g_maxValue; i++) {
			probabilities[flag][i] = 1;
		}
		// 第二個骰子到第n個骰子
		for (int k = 2; k <= number; k++) {
			flag = 1 - flag;
			// 當骰子數為k,那麼sum的範圍為k到k*g_maxValue
			for (int i = 1; i < k; i++) {
				probabilities[flag][i] = 0;
			}
			//k個骰子的最小和為k,k之前的數設為0;
			for (int i = k; i <= g_maxValue * k; i++) {
				int count = 1;
				//要把f(n)先設為0再進行計算
				probabilities[flag][i] = 0;
				while (i - count > 0 && count <= 6) {
					probabilities[flag][i] += probabilities[1 - flag][i - count];
					count++;
				}
			}
		}
		System.out.print("迴圈實現:");
		double total = Math.pow((double) g_maxValue, (double) number);
		// 打印出從number到maxSum每個數字出現的概率
		DecimalFormat df = new DecimalFormat("0.000");
		for (int i = number; i <= maxSum; i++) {
			System.out.print(df.format(probabilities[flag][i] / total) + " ");
		}
		System.out.println();
		long end = System.currentTimeMillis();
		long result = end - start;
		System.out.println("執行時間:" + result);
	}

}


相關推薦

n點數Java實現

本題為劍指offer面試題43 沒有找到牛客網的測試例題 題目:把n個骰子仍在地上,所有骰子朝上一面的點數之和為s,輸入n,打印出s的所有可能的值出現的概率。 解法一:基於遞迴求骰子的點數,時間效率不夠高 現在我們考慮如何統計每一個點數出現的次數。要向求出n個骰

找出兩字串中最大的公共java實現

import java.util.HashSet; import java.util.Set; public class Test { public static void main(String[] args) { String

N點數之和的分佈

將N個均勻的骰子,扔在地上,求點數之和的分佈。 因為是分佈,自然是求N個篩子之和等於M的概率,p(m) p(m) = fre(n,m)/sum fre(n,m)是指n個骰子扔出m個點數的 總的可能情況,這個就相當於組合數,只是限制了每個骰子的點數在1-6之間。 sum是n

n點數和及各自出現的概率

題目:把n個骰子扔在地上,所有骰子朝上一面的點數之和為S。輸入n,打印出S的所有可能的值出現的概率。 這道演算法題可採取動態規劃法來求解。鑑於《劍指Offer》中對該題的解法晦澀難懂,尤其是程式碼,也沒有指明其解題的思路本質上就是動態規劃,所以提出自己的理解和

最長公共序列Java實現——動態規劃

【問題描述】 給定2個序列X和Y,當另一序列Z既是X的子序列又是Y的子序列時,稱Z是序列X和Y的公共子序列。 給定2個序列X={A,B,C,B,D}和Y={B,D,C,A,B},找出X和Y的最長公共子序列{B,C,B}。 【分析】最長公共子序列問題具有最優子結構性質 設 X = {

LeetCode第23題:合併K有序連結串列JAVA實現

題目: 我的解答: 思路很簡單,把所有的資料先讀到ArrayList中然後轉到陣列中,然後排序,然後構建新連結串列 程式碼: /** * Definition for singly-linked list. * public class ListNode {

m元素的陣列,隨機選擇n不重複元素js實現

問題描述: 在由m個元素的source陣列中,隨機選擇n個不重複的元素放入新陣列target 注:source陣列元素本身不重複,m>n 解決方案 方案一: 根據陣列source,在0到source.length-1範圍內隨機一個數作為下標,

用兩棧模擬佇列java實現

要用兩個棧實現佇列,首先要明確棧和佇列的定義: 棧:只能在表尾進行插入刪除的線性表 佇列:只能在一端進行刪除,另一端進行插入的線性表 在明確棧和佇列的定義後,我們現在來討論它的具體實現過程: 對於棧而言,其遵循後進先出的原則(LIFO),後進的元素反而會最先彈出;而佇

《劍指offer》 面試題43 n點數 java

r+ nal ret 次循環 分而治之 源碼 ava 面試 ble 引言:寫這篇文章的初衷只是想做個筆記,因為這道題代碼量有點大,有點抽象,而書上並沒有詳細的註釋。為了加深印象和便於下次復習,做個記錄。 原題:把n個骰子扔到地上,所有骰子朝上一面的點數之後為s. 輸入n,打

劍指Offer面試題43Javan點數

pac pos max mod ins pri class pro bili 題目:把n個骰子仍在地上。全部骰子朝上一面的點數之和為s,輸入n,打印出s的全部可能的值出現的概率。 解法一:基於遞歸求骰子的點數,時間效率不夠高 如今我們考慮怎樣統計每個點數出現的次數。要向

劍指offer:n點數java

題目:把n個骰子仍在地上,所有骰子朝上一面的點數之和為s,輸入n,打印出s的所有可能的值出現的概率。     骰子一共6個面,每個面上都有一個點數,對應的是1-6之間的一個數字。所以n個骰子的點數和的最小值是n,最大值為6n.另外根據排列組合的知識,我們還知道n個骰子的所有

《劍指offer》第六十題n點數

original double 出現 ostream 使用 col ren str current // 面試題60:n個骰子的點數 // 題目:把n個骰子扔在地上,所有骰子朝上一面的點數之和為s。輸入n,打印出s // 的所有可能的值出現的概率。 #incl

常見連結串列操作-刪除連結串列倒數第n節點JAVA實現

問題 給出一個單向連結串列,刪除該連結串列倒數第n個節點,並返回頭節點。 例如: 給出連結串列 1->2->3->4->5,n=2 返回連結串列 1->2->3->5 解題思路 最容易想到的演算法: 先遍歷一次連結串列,

基於快排實現,在N亂序的陣列中找第K大的數Java實現

類似於快速排序,執行一次快速排序之後,每次只選擇一部分繼續執行快速排序,直到找到第K大個元素為止,這個元素在陣列位置後面的元素即為所求。 時間複雜度:O(n) 利用快排的思想,從陣列arr中隨機找出一個元素X,把陣列分成兩部分arr_a和arr_b。 arr_a中的元素比x大,arr_b中的元素比x小。 這

leetcode連結串列題--刪除連結串列的倒數第N節點java實現

原題 給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。 示例: 給定一個連結串列: 1->2->3->4->5, 和 n = 2. 當刪除了

n點數以及出現概率

//把n個骰子扔在地上,所有骰子朝上一面的點數之和為s。輸入n,打印出s的所有可能 //的值出現的概率。 #include "stdio.h" #include "cmath" #include "helper.h" using namespace std; //方法1:

n點數

把n個骰子扔在地上,所有骰子朝上一面的點數之和為s,輸入n,打印出s的所有可能出現的概率 思路:遞迴一般是自頂向下的分析求解,而迴圈則是自底向上,佔用更少的空間和更少的時間,效能較好。定義一個二維陣列,第一次擲骰子有6種可能,第一個骰子投完的結果存到probabilitie

【劍指offer】面試題43:n點數

第一種思路是,每個骰子的點數從最小到最大,假設為1-6,那麼所有的骰子從最小1開始,我們假設一種從左向右的排列,右邊的最低,索引從最低開始,判斷和的情況。 def setTo1(dices, start, end): for i in range(start, end)

n點數和出現的概率-動態規劃

這幾天在看劍指offer的時候發現,求n個骰子個點數和這個問題是發現書中講的不是很清楚,於是查詢資料,覺得下面講的比較透徹,記錄如下: 題目:把n個骰子扔在地上,所有骰子朝上一面的點數之和為S。輸入n,打印出S的所有可能的值出現的概率。 宣告思想非原創!只因動態規劃思

n點數之和的概率

n個骰子的點數。把n個骰子扔在地上,所有骰子朝上一面的點數之和為S。輸入n,打印出S的所有可能的值出現的概率。 思想:F(n,s) = F(n-1,s-6)+F(n-1,s-5)+F(n-1,s-4)+F(n-1,s-3)+F(n-1,s-2)+F(n-1,s-1); #i