这是悦乐书的第352次更新,第377篇原创
java
今天介绍的是LeetCode
算法题中Easy
级别的第214
题(顺位题号是914
)。在一副牌中,每张牌上都写有一个整数。算法
当且仅当您能够选择X >= 2
时才返回true
,以即可以将整个牌组分红一组或多组牌,其中:数组
每组都有X
张牌。数据结构
每组中的全部牌都具备相同的整数。测试
例如:优化
输入:[1,2,3,4,4,3,2,1]
输出:true
说明:可能的分区[1,1],[2,2],[3,3],[4,4]code
输入:[1,1,1,2,2,2,3,3]
输出:false
说明:没有可能的分区。递归
输入:[1]
输出:false
说明:没有可能的分区。get
输入:[1,1]
输出:true
说明:可能的分区[1,1]class
输入:[1,1,2,2,2,2]
输出:true
说明:可能的分区[1,1],[2,2],[2,2]
注意:
1 <= deck.length <= 10000
0 <= deck[i] <10000
题目的意思是将数组deck中的元素进行分组,值相等的划分为同一组,每一组中的元素个数都相等,且大于等于2。咱们可使用一个HashMap
,以deck
中的元素为key
,以其出现次数为value
,对HashMap
的value
值进行遍历。
最理想的状况,HashMap
中只有一组key-value
,但测试用例中确定不会这么轻易让你AC。来看几组例子分析下规律:
{1,1,1,2,2,2,3,3} {{1,1,1},{2,2,2},{3,3}} --> {3,3,2} {1,1,2,2,2,2,3,3,3,3,3,3} {{1,1},{2,2,2,2},{3,3,3,3,3,3}} --> {2,4,6}
第一个例子中,他们的最大公约数为1,即分组的组数存在奇偶分布的状况。
第二个例子中,他们的最大公约数为2,即分组的组数都是偶数,而且对于其中的4个2和6个3,是还能够继续拆分的,4个2拆成两组2个2,6个3拆成三组2个3。
所以,咱们只须要判断HashMap
中每对数据的最大公约数是否是等于1便可。
public boolean hasGroupsSizeX(int[] deck) { if (deck.length < 2) { return false; } Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int num : deck) { map.put(num, map.getOrDefault(num, 0)+1); } int count = 0; for (Integer value : map.values()) { if (value < 2) { return false; } if (count == 0) { count = value; } else { if (count != value) { int gcd = 1; for (int i=1; i<= count || i<=value; i++) { if (count%i == 0 && value%i == 0) { gcd = i; } } if (gcd == 1) { return false; } } } } return true; }
思路和第一种解法同样,只是将其中部分代码抽离了出来,而且简化了一些if-else
判断。
public boolean hasGroupsSizeX2(int[] deck) { if (deck.length < 2) { return false; } Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int num : deck) { map.put(num, map.getOrDefault(num, 0)+1); } int min = 10001; for (Integer num : map.values()) { min = Math.min(min, num); } if (min == 1) { return false; } for (Integer num : map.values()) { if (getGCD(min, num) == 1) { return false; } } return true; } public int getGCD(int a, int b) { int gcd = 1; for (int i=1; i<= a || i<=b; i++) { if (a%i == 0 && b%i == 0) { gcd = i; } } return gcd; }
由于限定了数组deck
中元素值范围,所以咱们可使用一个整型数组count
来计算deck
中各元素的出现次数,而后遍历count
中的元素,求出他们的最大公约数,只要有一对数的最大公约数等于1,就直接返回false。
public boolean hasGroupsSizeX3(int[] deck) { int[] count = new int[10001]; for (int num : deck) { count[num]++; } int temp = -1; for (int num : count) { if (num > 0) { if (num < 2) { return false; } if (temp == -1) { temp = num; } else { if (getGCD(temp, num) == 1) { return false; } } } } return true; } public int getGCD(int a, int b) { int gcd = 1; for (int i=1; i<= a || i<=b; i++) { if (a%i == 0 && b%i == 0) { gcd = i; } } return gcd; }
对第三种解法,咱们还能够再优化下,将求最大公约数的方法独立处理,而且用递归处理。
public boolean hasGroupsSizeX4(int[] deck) { int[] count = new int[10001]; for (int num : deck) { count[num]++; } int tem = count[deck[0]]; for (int num : count) { if (num > 0) { tem = gcd(tem, num); } } return tem > 1; } /** * 利用递归求a和b的最大公约数 * @param a * @param b * @return */ public int gcd(int a, int b) { return a == 0 ? b : gcd(b%a, a); }
算法专题目前已连续日更超过六个月,算法题文章220+篇,公众号对话框回复【数据结构与算法】、【算法】、【数据结构】中的任一关键词,获取系列文章合集。
以上就是所有内容,若是你们有什么好的解法思路、建议或者其余问题,能够下方留言交流,点赞、留言、转发就是对我最大的回报和支持!