1.题目描述
题目链接:https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 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,2,2,2,2] //==注意看这里的分组,相同数字是可以拆分的==
输出:true
解释:可行的分组是 [1,1],[2,2],[2,2]
提示:
1 <= deck.length <= 10000
0 <= deck[i] < 10000
2.题目分析
看完题目和数据规模,自然而然会想到用类似桶排序的思想,这只对了第一步,但很容易就不加思索地把问题考虑简单了,例如:
定义数组a[n],其中a[i]代表数字i出现的次数,然后遍历数组以确定数组前后值是否相等,即判断a[i]==a[i-1]
上面的思路有两个问题:
- 数字并不一定是逐一递增的
- 相同的数字是可以分组的(如示例二)
很(太)不(马)幸(虎),第二个问题我没有考虑到,WA了一次。看错误样例数字才知道是可以分组的,那数字怎么分组才能得出正确分法呢?
这种例子的特点就是,一部分数字次数多(M),一部分次数少(N),我们可以将次数多的一组进行分组,而分组的实质就是数字的拆分,我们想要的就是将大数字(M)分解成小数字(m),使得这个小数字跟原先的小次数相同。但还要注意,小次数(N)也是可以拆分成(n)的。
将两个数M,N进行拆分以获得最大的公共的因数部分,即最大公约数。
对于问题的a数组,我们就只需要判断gcd(a[i1],a[i2]...a[ik])>1
是否成立
3.代码如下
class Solution {
public:
bool hasGroupsSizeX(vector<int>& deck) {
int n=deck.size();
if (n==1) return false;
int a[10001];
for (int i=0;i<=10000;i++) a[i]=0;
for (int i=0;i<n;++i){
a[deck[i]]+=1;
}
int X=0;
for (int i=0;i<10000;++i){
if (a[i]==1) return false;
if (a[i]!=0){
if (X==0){
X=a[i];
}else{
X=gcd(X,a[i]);
if (X==1) return false;
}
}
}
return true;
}
int gcd(int x,int y) {
return !x?y:gcd(y%x,x);
}
};
4.补充
对于求最大公约数,c++里有很简单的写法:
return !x?y:gcd(y%x,x)
意思是如果现在x=0,那么就返回y的值;否则返回y%x和x的最大公约数。
欢迎讨论~爱宁(づ ̄ 3 ̄)づ