LeetCode914.卡牌分组——刷题日志
本人新手,今天每日一题刷到这个看了很久终于看懂了,就把自己的理解写下来,方便理清思路日后回忆。
题目描述
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:
每组都有 X 张牌。
组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。
示例 1:
输入:[1,2,3,4,4,3,2,1]
输出:true
解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]
示例 2:
输入:[1,1,1,2,2,2,3,3]
输出:false
解释:没有满足要求的分组。
示例 3:
输入:[1]
输出:false
解释:没有满足要求的分组。
示例 4:
输入:[1,1]
输出:true
解释:可行的分组是 [1,1]
示例 5:
输入:[1,1,2,2,2,2]
输出:true
解释:可行的分组是 [1,1],[2,2],[2,2]
提示:
1.1 <= deck.length <= 10000
2.0 <= deck[i] < 10000
题目解法
public static boolean hasGroupsSizeX(int[] deck) {
int []words=new int[10000];
for(int num:deck) {
words[num]++;
}
int x=0;
for(int word:words) {
if(word>0) {
x=gcd(x,word);
if(x==1) {
return false;
}
}
}
return x>=2;
}
private static int gcd(int a,int b) {
return b==0? a:gcd(b,a%b);
}
正如题目所述,可分为1组或者N组,每组间数目相同,组内要实现数字相同。
1.一组或者N组:这个对本题是没有影响的,因为题目的已经给出了条件1 <= deck.length <= 10000,所以只要有数字必定能至少为一组。
2.每组要实现数字相同,那么我们就可以创建一个计数数组,将相同的数存放在一起,并以该数为下标。
3.本题最关键的就是每组,组间的数目要相同,我们考虑几个例子:
[1,1,2,2]这是成立的,分组结果为[1,1][2,2]
[1,1,2,2,2,2]这也是成立的,分组结果为[1,1][2,2][2,2]
所以我们不能单单以不同计数数组的下标所对应的值为单位进行对等判断,如果上例,1有两个,2有四,如果只是仅仅将1分为一组,2分为一组显然是不成立的,所以我们要考虑他们的之前的最大公倍数。他们的公倍数为2,所以他们可以2个2个分为一组是成立的。
所以我们只要求得最大公倍数大于等于2即可以分组
如果存在等于1的情况则可以直接返回false
公倍数
private static int gcd(int a,int b) {
return b==0? a:gcd(b,a%b);
}
这是公倍数求法的通式。
至于公倍数的求法
用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。
详细请见下图领会:
我原本纠结于之前都是说较大的数除以较小的数,但是我发现好像反了也关系。
12 除以13 余12
那么接下来的迭代就是
13除以12
外链图片转存中…(img-4b65TB1T-1585321240765)]
我原本纠结于之前都是说较大的数除以较小的数,但是我发现好像反了也关系。
12 除以13 余12
那么接下来的迭代就是
13除以12
还是自动会变成较大的数除以较小的数