[Leetcode]最大公约数--卡牌分组

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]

上面的思路有两个问题:

  1. 数字并不一定是逐一递增的
  2. 相同的数字是可以分组的(如示例二)

很(太)不(马)幸(虎),第二个问题我没有考虑到,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 ̄)づ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值