1. 程式人生 > >程序模擬洗撲克牌(算法)

程序模擬洗撲克牌(算法)

相交 arr 基礎上 contain 關心 人才 ray 面試 eat

前一段時間找實習,騰訊面試中一輪面試官被問到這個題目,我回答了以下解法中的第一種,太搓了。直接遭面試官歧視了,回來搜了搜,發現一種更好的解法(以下解法中的另外一種)。今天偶爾發現解法2事實上有毛病。於是改進了。有了算法3和算法4.

前提:一副撲克牌有54張。因此我們能夠一個整型數組array[54]或者map來存儲。"A"用0~3,"2"用4~7,"3"用8~11......"K"用48~51,小鬼用52,大鬼用53表示。關於花色,我們能夠這樣表示:4i表示紅桃,4i+1表示黑桃。4i+2表示梅花。4i+3表示方塊(0<=i<=12)。這種話。就退化成一個數組問題。而不關心其表示形式。從而達到邏輯與表現形式脫離。

解法1:隨機產生0~53的亂數並將之存入數組中,後來產生的亂數存入數組前必須先檢查數組中是否已有反復的數字,假設有這個數字就不存入。在又一次產生下一個數。

	//使用hashmap。目的是為了加快查找速度,hashmap中的key即為撲克牌序列
	//產生隨機數,若該隨機數在hashmap有。則一直生成隨機數,直到沒有為止
	public int [] Create_1(){
		HashMap<Integer,Integer> hashmap=new HashMap<Integer,Integer>();
		int [] array =new int [54];
		Random rand;
		int num;
		
		for(int i=0;i<cardNum;i++){
			rand=new Random(System.currentTimeMillis());
			num=rand.nextInt(cardNum-1);
			
			while(hashmap.containsKey(num)){
				rand=new Random(System.currentTimeMillis());
				num=rand.nextInt(cardNum-1);
			}
			hashmap.put(num, i);
			array[i]=num;
		}
		
		return array;
	}
分析:隨著產生的隨機數的數目的添加,可以正確生成下一個隨機數的概率在下降,比方說能正確生成第一個數的概率是54/54,能正確生成第二個數的概率降為53/54,能正確生成第i個數的概率變為(55-i)/54,能正確生成最後一個數的概率是1/54,這種話就須要遠不止54次了。


解法2:將數組先依序由0到53填入,然後使用一個回圈走訪數組。並隨機產生0~53的亂數。將產生的亂數當作索引取出數組值,並與眼下數組走訪到的值相交換。

	//依靠交換數組中的兩個值
	public int [] Create_2(){
		int [] array=new int [cardNum];
		Random rand;
		int num;
		
		for(int i=0;i<array.length;i++){
			array[i]=i;
		}
		
		for(int i=0;i<array.length;i++){
			rand=new Random(System.currentTimeMillis());
			num=rand.nextInt(cardNum-1);
			array[num]=i;
			array[i]=num;	
		}
		
		return array;
	}
	
分析:算法2的確比算法1快非常多。並且看起來像是正確的。事實上生成的某個序列在全部序列中並非等可能的。

終於可能的序列有n!

種,而在交換的過程中。有n^n種,這樣當n>2時。n^n/(n!)並不為一個整數。因此生成序列的概率並不相等。


算法3:在算法2的基礎上改進,我們僅僅交換當前須要交換的和後面沒有交換的。

	//依靠交換數組中的兩個值
	// 僅僅交換i和i後面的
	public int [] Create_3(){
		int [] array=new int [cardNum];
		Random rand;
		int num;
		
		for(int i=0;i<array.length;i++){
			array[i]=i;
		}
		
		for(int i=0;i<array.length;i++){
			rand=new Random(System.currentTimeMillis());
			num=i+rand.nextInt(cardNum-i);
			array[num]=i;
			array[i]=num;	
		}
		
		return array;
	}
分析:該算法是正確,並且效率比較高。實際上我們能夠使用庫函數。從而達到更高的效率。


算法4:使用庫函數,效率更高。

	public int [] Create_4(){
		int [] array=new int [cardNum];
		for(int i=0;i<array.length;i++){
			array[i]=i;
		}
		
		Collections.shuffle(Arrays.asList(array));
		return array;
	}
總結:以上的四種想法是一步步的改進與提煉,隨著時間的增長。人才會慢慢成長吧。

程序模擬洗撲克牌(算法)