leetcode--914.卡牌分组

题目描述:
在这里插入图片描述
示例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]

思路:

首先先感慨一下:

这个题对于我太困难了,做了三个多小时
不过幸好自己没放弃!

思路:
我的错误思路:
一开始我想着直接将整个数组排序,然后统计第一个非0元素出现的次数,记为sum,让它成为一个基准,后面的的数字都依次统计出现的次数numbers,如果所有的numbers%sum==0,那么说明这个数组的可行的分组,返回true,不然返回false.
但是这只是很单纯的想法,实际上存在很多种"特殊"的情况,比如[1,1,1,1,2,2,2,2,2,2],对于这种情况,如果按照我的想法的话,返回的就是false,但是这个数组可以分为[[1,1][1,1][2,2][2,2][2,2]],所以第一种思路本质上就是错的。没有考虑到诸如此类情况。

我的正确思路:
(1) 创建一个和原数组等长的数组,记为shuzu
(2) for循环遍历原数组的每一个元素,将元素的值存入到新数组中自身值所对应的角标的单元中,即shuzu[deck[i]]++。这样,就可以统计出来原数组中相同数字出现的次数了。
(3) for循环遍历shuzu中的每一个元素, 找到第一个非0元素,记下该元素的值shuzu[m]和角标m,在这里进行一个判断,就是:如果shuzu[m]==1,说明有组的"牌数"小于2,不符合题意,直接返回false
(4) 接着就是重要的步骤了:
定义一个boolean类型的flag变量,初始值为true.定义一个int类型的计数变量count,初始值为0
定义两个for循环,外层for循环(n=2;n<=shuzu[m];n++),内层for循环(k=m+1;k<shuzu,length;k++)
在内层for循环和外层for循环中间将flag赋值为true。

那这样做是为了什么?
答:因为在错误思路中,我忽略了[1,1,1,1,2,2,2,2,2,2]这种情况的问题,不能只靠单纯的计数取余进行比较,所以我定义n,让n从2开始依次"遍历"最小值出现的次数(shuzu[m]),如果存在一个n,使得shuzu[m]%n==0并且shuzu[m+1],shuzu[m+2],shuzu[m+3].......shuzu[shuzu.length-1]的每一个值对n取余都等于0,那么说明这个数组是可行分组。即针对最小值shuzu[m]和最小值后面的数组元素的公约数的判断,只要存在一个公约数满足上面的情况,就返回true,如果所有的公约数都不满足上面的条件,即不存在一个n满足,那么返回false(5) 下来的过程就是检查是否存在一个n(公约数)满足条件,或者所有的n(公约数)都不满足.所以定义flag进行判断标记
   回顾一下最重要且需要同时满足的两个条件:存在的n,使得shuzu[m]%n==0&&shuzu[m+1],shuzu[m+2],shuzu[m+3].......shuz[shuzu.length-1]的每一个值对n取余都等于0
   
在内层循环中,第一个if语句是判断现在循环的n,是否满足shuzu[m]%n==0.
 如果shzu[m]%n!=0,说明当前的n不符合两个条件中的第一个,那么让count++,flag=false,并且break.
 如果shuzu[m]%n==0,满足第一个条件,接下来判断是否shuzu中剩余的元素都能整除n,如果有一个不满足,那么也和上面一样,令count++,令flag=false,并且break.
 当前内层循环执行完毕.但是存在两种情况:
一种是正常循环退出for循环的,并且flag=true;
一种是被break退出for循环的,并且flag=flase.
那就需要进行判断:
如果flag是true,那么说明有一个n满足上面的两个条件,直接break跳出外层循环,也就是说明存在可行性分组;
如果flag是false,说明当前的n不满足,同时还有一个if判断语句:如果count==shuzu[m]-1,说明所有的n都循环完了都不满足上面的两个条件,直接break跳出外层循环,也就是说明并不存在可行性分组,如果count!=shuzu[m]-1,说明n的情况并没有判断完,即n并没有"循环",那么继续通过外层循环,使得n++,继续进行判断,看当前的n是否满足这两个条件。接着就是循环上面的步骤,直到满足条件跳出外层循环,即flag是true或者false,即可行分组和不可行分组.

java代码

class Solution {
    public boolean hasGroupsSizeX(int[] deck) {
        if(deck.length==1){
            return false;
        }
        int[] shuzu = new int[deck.length];
         for(int i=0;i<deck.length;i++){
             shuzu[deck[i]]++;
         }
         Arrays.sort(shuzu);
         int m=0;
         for(int j=0;j<shuzu.length;j++){
             if(shuzu[j]!=0){
                 m=j;
                 break;
             }
         }
         if(shuzu[m]==1){
             return false;
         }
         boolean flag=true;
         int count=0,n=0,k=0;
         for(n=2;n<=shuzu[m];n++){
             flag=true;
         for(k=m+1;k<shuzu.length;k++){
                 if(shuzu[m]%n==0){
                 if(shuzu[k]%n!=0){
                     flag=false;
                     count++;
                     break;
                 }
                 }else{
                     flag=false;
                     count++;
                     break;
                 }
             }
             if(flag!=true){
                 if(count==shuzu[m]-1){
                break;
            }
             }else{
                 break;
             }
         }
         return flag;  
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值