字节跳动2019春招试题三——雀魂
题目来自牛客网,感谢!
从1~9每种4张共36张的麻将中取出13张,将能和牌的第14张牌的可能取值输出
满足以下条件能够和牌:
- 有2张数字相同,称为雀头
- 余下的12张构成4组顺子或刻子,顺子指形如123、567等,刻子指形如111、888等
输入格式:
第一行输入用空格分隔的13个数字
输入保证每个数字在1~9之间,且相同数字最多出现4次。
输出格式:
第一行输出1个或以上的数字,代表使牌面和牌的第14张牌的可能取值
若不存在,输出0;若多于1个,从小到大按序输出
输入范例:
1 1 1 1 2 2 3 3 5 6 7 8 9
输出范例:
4 7
由于数据局限在1~9,首先就考虑到用基数来处理数据。令1~9循环作为第14张牌进行和牌判定。
一开始在形为122333445的形式处有点纠结,因为这意味着数据量为3的时候不能直接消去,后来意识到基数按序消去的时候,顺子均会在顺子顺序里的第一个数处被检出并消去,因此3的情况只需考虑消去即可。
这里进行了第一轮测试,发现没考虑雀头。加上雀头之后整体的讨论变得非常复杂,用了偷懒的方式,检索基数,凡是检索到多于2的位置令其-2后再进行顺子刻子判定。
这里进行了第二轮测试,遇到了最后一个问题:由于未考虑到形为112233的形式,导致武断地认定顺刻判定时只有2的时候是必然不成顺刻的。意识到这个问题并修改,成功通过了OJ。
我的代码实现:
import java.util.Scanner;
public class Majiang{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] a = new int[13];
for (int i = 0; i < 13; i++)
a[i] = sc.nextInt();
sc.nextLine();
sc.close();
int[] num = new int[9];
for (int i = 0; i < 9; i++)
num[i] = 0;
for (int i = 0; i < 13; i++)
num[a[i] - 1]++;
int trigger = 0;
for (int i = 0; i < 9; i++) {
if (num[i] == 4)
continue;
if (check2(num, i)) {
if (trigger > 0)
System.out.print(" ");
System.out.print(i + 1);
trigger++;
}
}
if (trigger == 0)
System.out.println(0);
}
public static boolean check2(int[] num, int p) {
int[] x = new int[9];
for (int i = 0; i < 9; i++)
x[i] = num[i];
x[p]++;
for (int i = 0; i < 9; i++)
if (x[i] >= 2)
if (check(x, i))
return true;
return false;
}
public static boolean check(int[] num, int p) {
int[] x = new int[9];
for (int i = 0; i < 9; i++)
x[i] = num[i];
x[p] -= 2;
for (int i = 0; i < 9; i++) {
if (x[i] >= 3)
x[i] -= 3;
if (x[i] == 2)
if (i + 2 < 9 && x[i + 1] > 0 && x[i + 2] > 0) {
x[i]--;
x[i + 1]--;
x[i + 2]--;
} else
return false;
if (x[i] == 1)
if (i + 2 < 9 && x[i + 1] > 0 && x[i + 2] > 0) {
x[i]--;
x[i + 1]--;
x[i + 2]--;
} else
return false;
}
return true;
}
}
PS:写的时候不知道麻将的日语说法是什么,印象中好像是麻将发音的片假名,姑且写了个Majiang作为类名,不过也不打算去查了哈哈哈