码迷,mamicode.com
首页 > 其他好文 > 详细

程序模拟洗扑克牌(算法)

时间:2014-07-06 09:06:37      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:java   算法   

前一段时间找实习,腾讯面试中一轮面试官被问到这个题目,我回答了下面解法中的第一种,太搓了,直接遭面试官鄙视了,回来搜了搜,发现一种更好的解法(下面解法中的第二种),今天偶尔发现解法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;
	}
总结:以上的四种想法是一步步的改进与提炼,随着时间的增长,人才会慢慢成长吧。

程序模拟洗扑克牌(算法),布布扣,bubuko.com

程序模拟洗扑克牌(算法)

标签:java   算法   

原文地址:http://blog.csdn.net/mlweixiao/article/details/36928431

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!