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