Leetcode:914. 卡牌分组
Leetcode:914. 卡牌分组
1、题目描述
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:
- 每组都有 X 张牌。
- 组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。
2、 思路
- 题目文字和示例 3 和告诉我们:如果检测到某个组里元素只有 1 个,可以直接返回 false。
- 示例 5 非常特殊,是一个很重要的示例,[2, 2, 2, 2] 硬是被拆成了 2 组,为的是与组 [1, 1] 的元素个数相等。这对应了题目「每组都有 X 张牌」 的要求。
- 遍历一次,统计每个数值的个数,如果某个数值只有 1 个,直接返回 false;
- 再看一下示例 5,想更一般化的情况,输入 [2, 2, 2, 2, 3, 3, 3, 3, 3, 3],其实也是符合题意的分组,2 有 44 个,3 有 66 个,相同的 2 和 3 都需要拆成 2 个一组,因此这里的 X = 2,很显然 22 是这两个组的元素个数的公约数。
3、过程
- 得到传入数组的所有个数,如果个数为1,则直接返回false
int len = deck.length;
if (len < 2) {
return false;
}
- 开始计数,求出每个数出现的次数,并用数组来标记即可。
int[] cnt = new int[10000];
for (int num : deck) {
cnt[num]++;
}
- 利用变量接收下第一个数出现的次数,然后遍历整个计数的数组,如果这个数组里面有一个数为1,直接返回false,如果不为1,那就传入gcd函数中。
int x = cnt[deck[0]];
for (int i = 0; i < 10000; i++) {
if (cnt[i] == 1) {
return false;
}
if (cnt[i] > 1) {
x = gcd(x, cnt[i]);
// 这里做判断可以提前终止运行,也可以等到最后再做,各有优劣,任选其一
if (x == 1) {
return false;
}
}
}
- 书写gcd(int a, int b)函数,其实这个函数的作用就是求出公约数,并返回公约数。
private int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
具体代码如下:
/** * 给定一副牌,每张牌上都写着一个整数。 * * 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组: * * 每组都有 X 张牌。 * 组内所有的牌上都写着相同的整数。 * 仅当你可选的 X >= 2 时返回 true。 */
public class p914 {
/** * * @param deck 给定一副牌数组 * @return 仅当你可选的 X >= 2 时返回 true。 */
public boolean hasGroupsSizeX1(int[] deck) {
int len = deck.length;
if (len < 2) {
return false;
}
// 计数数组,10000 是根据题目给出的数值范围定的
int[] cnt = new int[10000];
for (int num : deck) {
cnt[num]++;
}
// 先得到第 1 个数的个数,以避免在循环中赋值
int x = cnt[deck[0]];
for (int i = 0; i < 10000; i++) {
if (cnt[i] == 1) {
return false;
}
if (cnt[i] > 1) {
x = gcd(x, cnt[i]);
// 这里做判断可以提前终止运行,也可以等到最后再做,各有优劣,任选其一
if (x == 1) {
return false;
}
}
}
return true;
}
private int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
public static void main(String[] args) {
int[] deck = new int[]{
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3};
p914 test = new p914();
System.out.println(test.hasGroupsSizeX1(deck));
}
}