【914】卡牌分组(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,1,2,2,2,3,3]
输出:false
解释:没有满足要求的分组。

个人思路:拿到一个数组,第一步肯定是要计算每个值的个数,假设1有a个,2有b个,3有c个,4有d个,要满足题目条件,其本质就是找a,b,c,d有没有公约数(1除外)。
例如示例1,对应的就是a=2,b=2,c=2,d=2,有一个公约数2所以是True

C#

public bool HasGroupsSizeX(int[] deck) 
{
    //1:总长度小于2直接返回
    if (deck.Length < 2) 
        return false;

    //2:统计每个数出现的次数
    //Key:该数字。   Value:该数字出现的次数
    Dictionary<int, int> NumcntDic = new Dictionary<int, int>();
    //遍历数组
    for (int i = 0; i < deck.Length; i++)
    {
        //字典键中是否包含当前数,包含,即该数已存在,则加一,不包含,即不存在,则赋值为1
        NumcntDic[deck[i]] = NumcntDic.ContainsKey(deck[i]) ? NumcntDic[deck[i]] + 1 : 1;
    }

    //3:找到字典值集合中的最小值
    int minCnt = NumcntDic.Values.Min();
    //如果最小值小于二,则返回false
    if (minCnt < 2) 
        return false;

    //若最小则是a,其他值是b
    //若满足条件,则a和b中有一个大于1的公约数
    //eg:如果最小值a=6,其他值b=15。因为a=6=2*3,b=15=3*5,存在一个大于1的公约数3
    //所以可以每组分配3个,符合条件,返回true

    //4:找到最小值a的约数大于1的集合
    //公约数集合
    List<int> comList = new List<int>();
    //从1开始,到minCnt的算术平方根结束
    for (int i = 1; i <= Math.Sqrt(minCnt); i++) 
    {
        //取余等于0
        if (minCnt % i == 0) 
        {
            //只记录大于1的约数
            if (i > 1)
                comList.Add(i);
            //若i与其对应的约数不同,则添加
            if (i != minCnt / i) 
                comList.Add(minCnt / i);
        }
    }
    //遍历所有其他值b
    foreach (int curCnt in NumcntDic.Values)
    {
        //相同不用计算
        if (curCnt != minCnt) 
        {
            //遍历最小值约数集合
            //由于遍历时,移除元素不方便
            //所以规定:集合中已舍去的约数用-1代替
            for (int i = 0; i < comList.Count; i++)
            {
                if (comList[i] != -1)
                {
                    //当前约数是公约数,则继续查找
                    if (curCnt % comList[i] == 0)
                        continue;
                    //当前约数不是公约数,则舍去,赋值为-1
                    comList[i] = -1;
                }
            }
        }
    }

    //最后检查约数集合里是否含有非-1值
    return comList.Any(com => com != -1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值