題目:
從一副撲克牌中隨機抽取5張牌 判斷這五張牌是否是一個同花順
同花順:點數連續 花色相同
大小王可以當做任意點數任意花色的牌
簡單陳述一下思路
package cn.yangwanhao.writtenexamination;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
* 題目:從一副牌中隨機抽取五張牌,判斷是否為同花順(連續的同花色五張)
* 題目只要求描述思路,這里順帶用代碼實現一下
*
* @author 楊萬浩
* @since 2020/6/27 17:22
*/
public class FlushTest {
private static final String SPADE = "黑桃";
private static final String HEART = "紅桃";
private static final String CLUB = "梅花";
private static final String DIAMOND = "方塊";
private static final String JOKER = "大小王";
private static final String[] TYPES = new String[] {
SPADE, HEART, CLUB, DIAMOND
};
private static final int PAPER_NUM = 5;
public static void main(String[] args) throws InterruptedException {
/*
* 題目要求:從54張牌中隨機抽取五張,判斷是否為同花順,其中大小王可以當做任意牌
* 同花順:點數連續的五張同花色的牌(五張,點數連續,同花色)
*/
// 隨機抽取的方法在下面注釋掉了,使用Random實現,太過隨緣(成功率太低),這里使用幾組數據模擬
// 這里使用11代表J 12代表Q 13代表K 14代表小王 15代表大王 大小王的type為“王”
// 准備數據
// 第一組數據 不通過 花色不同
List<PaperCard> testList1 = new ArrayList<>(PAPER_NUM);
testList1.add(new PaperCard(1, SPADE));
testList1.add(new PaperCard(2, SPADE));
testList1.add(new PaperCard(3, CLUB));
testList1.add(new PaperCard(4, SPADE));
testList1.add(new PaperCard(15, JOKER));
// 第二組數據 通過 有一個小王
List<PaperCard> testList2 = new ArrayList<>(PAPER_NUM);
testList2.add(new PaperCard(8, HEART));
testList2.add(new PaperCard(9, HEART));
testList2.add(new PaperCard(11, HEART));
testList2.add(new PaperCard(12, HEART));
testList2.add(new PaperCard(14, JOKER));
// 第三組數據 不通過 有一個大王但是中間差值為2
List<PaperCard> testList3 = new ArrayList<>(PAPER_NUM);
testList3.add(new PaperCard(3, DIAMOND));
testList3.add(new PaperCard(4, DIAMOND));
testList3.add(new PaperCard(7, DIAMOND));
testList3.add(new PaperCard(8, DIAMOND));
testList3.add(new PaperCard(15, JOKER));
// 第四組數據 通過 中間差值為2 但是有兩個王
List<PaperCard> testList4 = new ArrayList<>(PAPER_NUM);
testList4.add(new PaperCard(4, HEART));
testList4.add(new PaperCard(14, JOKER));
testList4.add(new PaperCard(6, HEART));
testList4.add(new PaperCard(15, JOKER));
testList4.add(new PaperCard(8, HEART));
// 執行測試
System.out.println(isFlush(testList1));
System.out.println(isFlush(testList2));
System.out.println(isFlush(testList3));
System.out.println(isFlush(testList4));
/*
* 下邊是模擬抽取五張牌的代碼 但是這個太隨緣了 成功率太低 所以手動使用集合來測試
*/
/*boolean flag = true;
int executeCount = 0;
do {
executeCount++;
List<PaperCard> paperCards = getPaperCards();
System.out.println(paperCards);
Boolean flush = isFlush(paperCards);
System.out.println(flush);
if (flush) {
flag = false;
}
// 為防止生成的隨機數太過相近,讓線程休眠一下
Thread.sleep(50);
} while (flag);
System.out.println("總執行次數:" + executeCount);*/
}
private static List<PaperCard> getPaperCards() {
Random random = new Random();
List<PaperCard> paperCardList = new ArrayList<>(PAPER_NUM);
do {
PaperCard paperCard = new PaperCard();
// 隨機產生點數
int num = random.nextInt(15) + 1;
// 14 15 只能產生一次(按理說其他點數也只能產生4次 但是這里就不處理了)
if (num == 14 || num ==15) {
if (paperCardList.contains(num)) {
continue;
}
paperCard.num = num;
paperCard.type = JOKER;
} else {
// 隨機產生花色
int type = random.nextInt(4);
paperCard.num = num;
paperCard.type = TYPES[type];
}
paperCardList.add(paperCard);
// 湊夠五張牌后返回
} while (paperCardList.size() < 5);
return paperCardList;
}
private static Boolean isFlush(List<PaperCard> paperCardList) {
/*
* 思路:
* ①五張牌按照點數去重並排序,去重后不等於5則false
* ②判斷五張牌的花色是否相同,去重后不等於1或者去重后等於2但不包含大小王則false(因為JOKER可以當做任意花色,所以可以出現大小為2)
*/
// 這里使用兩個TreeSet來分別存儲五張牌的點數和花色(TreeSet天然不重復且自然有序)
// 點數使用TreeSet來創建是為了在下邊使用TreeSet的first()和last()方法,這是TreeSet獨有的
TreeSet<Integer> numSet = new TreeSet<>();
Set<String> typeSet = new TreeSet<>();
for (PaperCard p : paperCardList) {
numSet.add(p.num);
typeSet.add(p.type);
}
// 因為點數必然都不相同 所以如果不是五張牌就false
if (numSet.size() != PAPER_NUM) {
return false;
}
// 花色這里JOKER可以當做任意花色 所以需要多判斷一個條件
if (typeSet.size() != 1 && !(typeSet.size() == 2 && typeSet.contains(JOKER))) {
return false;
}
// 經過上邊兩重判斷 此時五張牌必然點數不同且花色相同 接下來就是判斷點數是否連續
// 首先移除大小王
numSet.remove(14);
numSet.remove(15);
// 獲取剩余的TreeSet的最大值和最小值
int difference = numSet.last() - numSet.first();
// 三種情況是通過的
// 沒有王 集合長度是5,差值應該為4 eg:4,5,6,7,8 5,6,7,8,9 9,10,11,12,13
// 一個王 集合長度是4,差值應該為4或者3 eg:4,5,7,8,14 1,2,3,4,14
// 兩個王 集合長度是3,差值應該為4或者或者3或者2 eg:1,3,5,14,15 1,3,4,14,15 1,2,3,14,15
// 由此可以觀察出 差值的范圍應該是 4 >= difference >= numSet.size()-1
if (difference <= PAPER_NUM-1 && difference >= numSet.size()-1) {
return true;
}
/*if (numSet.size() == 5 && difference == 4) {
return true;
}
if (numSet.size() == 4 && (difference == 4 || difference == 3)) {
return true;
}
if (numSet.size() == 3 && (difference == 4 || difference == 3 || difference == 2)) {
return true;
}*/
return false;
}
@NoArgsConstructor
@AllArgsConstructor
static class PaperCard {
/**
* 點數
*/
private Integer num;
/**
* 花色
*/
private String type;
@Override
public String toString() {
return "("
+ num + "," + type
+ ")";
}
}
}
使用getPaperCards()方法測試太過隨緣,我簡單的測試了幾次,最快的一次33次就生成了一個同花順,最慢的一次3756次才生成一個同花順
所以在代碼中使用給定的幾組數據進行測試