一、算法问题描述
随机取6张牌,牌上的数字为 0 ~ 9,可以重复,组成 baby-gin算法的条件:1个run + 1 个trip或者2个run或者2个trip 类型
一种组合为 run(1,2,3),三张牌为顺子,另一种为trip(1,1,1),三张牌相同。
二、算法分析
1.暴力查询法(慢)
(1).先从6张牌中任意选取3张自由组合,也就是C6(3),共有20种不同的组合。
public class BabyGin {
public static void main(String[] args){
int[] baby = {1,3,5,6,2,2};
BabyGin.select3(baby);
}
// 从 6 张牌中任意选取3张
public static int[] select3(int[] baby6){
int[] baby3 = new int[3]; // 创建一个存放组合的数组
int count = 0;
for(int i = 0;i < baby6.length - 2;i++){
for(int j = i+1;j < baby6.length - 1;j++){
for(int k = j+1;k < baby6.length;k++){
baby3[0] = baby6[i];
baby3[1] = baby6[j];
baby3[2] = baby6[k];
// 20种排好序
System.out.println("第" + (count+1) + "种,[" + baby3[0] + "," + baby3[1] + "," + baby3[2] + "]");
count++;
}
}
}
return baby3;
}
}
(2).将组合起来的20种组合分别排序,建议从小到大排序。
// 冒泡排序,将选取的3张牌从小到大排序
public static int[] bubble(int[] select3){
for(int i = 0;i < select3.length - 1;i++){
for(int j = i + 1;j < select3.length;j++){
if(select3[i] > select3[j]){
int temp = select3[j];
select3[j] = select3[i];
select3[i] = temp;
}
}
}
return select3;
}
(3).判断是否符合baby-gin算法需求,有一种run/trip组合,就计一次数,计满2次就符合baby-gin算法。
// 判断是否为 run / trip,前提条件是传入的数组已经从小到大排好序
public static boolean countRunOrTrip(int[] bubble) {
boolean flag = false;
if (bubble[0] == (bubble[1] - 1)) {
if (bubble[1] == (bubble[2] - 1)) {
flag = true;
}
} else if (bubble[0] == bubble[1]) {
if (bubble[1] == bubble[2]) {
flag = true;
}
}
return flag;
}
(4) 最终代码
package com.daxiong.encode;
public class BabyGin {
public static void main(String[] args) {
int[] baby = { 1, 1, 2, 2, 3, 3 };
BabyGin.select3(baby);
}
// 从 6 张牌中任意选取3张
public static int[] select3(int[] baby6) {
int[] baby3 = new int[3]; // 创建一个存放组合的数组
int count = 0;
int yesCount = 0;
for (int i = 0; i < baby6.length - 2; i++) {
for (int j = i + 1; j < baby6.length - 1; j++) {
for (int k = j + 1; k < baby6.length; k++) {
baby3[0] = baby6[i];
baby3[1] = baby6[j];
baby3[2] = baby6[k];
// 20种排好序
System.out.println("第" + (count + 1) + "种,[" + baby3[0] + "," + baby3[1] + "," + baby3[2] + "]组合");
int[] bubble = BabyGin.bubble(baby3);
System.out.print("排序后,[" + bubble[0] + "," + bubble[1] + "," + bubble[2] + "]");
boolean flag = BabyGin.countRunOrTrip(bubble);
System.out.print(" ," + flag);
System.out.println();
if (flag) {
yesCount++;
}
count++;
}
}
}
if (yesCount >= 2) {
System.out.println("YES 该数组为 baby-gin");
} else {
System.out.println("NO 该数组不是 baby-gin");
}
return baby3;
}
// 冒泡排序,将选取的3张牌从小到大排序
public static int[] bubble(int[] select3) {
for (int i = 0; i < select3.length - 1; i++) {
for (int j = i + 1; j < select3.length; j++) {
if (select3[i] > select3[j]) {
int temp = select3[j];
select3[j] = select3[i];
select3[i] = temp;
}
}
}
return select3;
}
// 判断是否为 run / trip,前提条件是传入的数组已经从小到大排好序
public static boolean countRunOrTrip(int[] bubble) {
boolean flag = false;
if (bubble[0] == (bubble[1] - 1)) {
if (bubble[1] == (bubble[2] - 1)) {
flag = true;
}
} else if (bubble[0] == bubble[1]) {
if (bubble[1] == bubble[2]) {
flag = true;
}
}
return flag;
}
}
2.计数法(高效,快速)
(1).先统计给定6张牌出现0~9的次数,并记录
// 统计0~9出现的频率
public static int[] countHZ(int[] baby){
int[] baby09 = {0,0,0,0,0,0,0,0,0,0}; // 0 ~ 9 出现的次数
for(int i = 0;i < baby.length;i++){
for(int j = 0; j < 9;j++){
if(baby[i] == j){
baby09[j] = baby09[j] + 1;
}
}
}
return baby09;
}
(2)判断是否为 baby-gin 算法
需要注意:112233,这种情况,当判断0~9中123的个人分别都大于0时,同时减去1,还回剩下123,此时需要再次调用该方法,才会执行,所以这里采用递归调用的方式,如果调用完第一次后0~9中频率还大于0,此时再次调用
// 判断是否为 baby-gin 算法
public static int countBabyGin(int[] baby09) {
int count = 0;
int flag = 0;
for (int i = 0; i < baby09.length - 2; i++) {
if (baby09[i] >= 3) { // 说明至少有一个 trip
baby09[i] = baby09[i] - 3;
count++;
} else if (baby09[i] > 0 && baby09[i + 1] > 0 && baby09[i + 2] > 0) {
baby09[i] = baby09[i] - 1;
baby09[i + 1] = baby09[i + 1] - 1;
baby09[i + 2] = baby09[i + 2] - 1;
count++;
}
if (baby09[i] != 0) {
flag++;
}
}
System.out.println("flag =" + flag);
for (int i = 0; i < 9; i++) {
System.out.println("baby09 =" + baby09[i]);
}
if(flag > 0){ // 递归调用,需要注意递归调用结束的条件
count = count + BabyGin2.countBabyGin(baby09);
}
return count;
}
(3)整体代码
package com.daxiong.encode;
public class BabyGin2 {
public static void main(String[] args) {
int[] baby = { 1, 1, 2, 2, 3, 3 };
System.out.println(BabyGin2.countBabyGin(BabyGin2.countHZ(baby)));
int[] baby09 = BabyGin2.countHZ(baby);
int countFlag = BabyGin2.countBabyGin(baby09);
if(countFlag >= 2){
System.out.println("YES 该数组为 baby-gin");
} else{
System.out.println("NO 该数组不是 baby-gin");
}
}
// 统计0~9出现的频率
public static int[] countHZ(int[] baby) {
int[] baby09 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 0 ~ 9 出现的次数
for (int i = 0; i < baby.length; i++) {
for (int j = 0; j < 9; j++) {
if (baby[i] == j) {
baby09[j] = baby09[j] + 1;
}
}
}
return baby09;
}
// 判断是否为 baby-gin 算法
public static int countBabyGin(int[] baby09) {
int count = 0;
int flag = 0;
for (int i = 0; i < baby09.length - 2; i++) {
if (baby09[i] >= 3) { // 说明至少有一个 trip
baby09[i] = baby09[i] - 3;
count++;
} else if (baby09[i] > 0 && baby09[i + 1] > 0 && baby09[i + 2] > 0) {
baby09[i] = baby09[i] - 1;
baby09[i + 1] = baby09[i + 1] - 1;
baby09[i + 2] = baby09[i + 2] - 1;
count++;
}
if (baby09[i] != 0) {
flag++;
}
}
System.out.println("flag =" + flag);
for (int i = 0; i < 9; i++) {
System.out.println("baby09 =" + baby09[i]);
}
if(flag > 0){ // 递归调用,需要注意递归调用结束的条件
count = count + BabyGin2.countBabyGin(baby09);
}
return count;
}
}