给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X
,使我们可以将整副牌按下述规则分成 1 组或更多组:
- 每组都有
X
张牌。 - 组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2
时返回 true
。
示例 1:
输入:deck = [1,2,3,4,4,3,2,1] 输出:true 解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]
示例 2:
输入:deck = [1,1,1,2,2,2,3,3] 输出:false 解释:没有满足要求的分组。
欧几里得算法,把数学又学了一遍
//欧几里得算法,把数学又学了一遍
function hasGroupsSizeX(deck: number[]): boolean {
//每种牌出现的次数
const deckTimesMap = new Map<number, number>();
//记录次数
for (const d of deck) {
const v = (deckTimesMap.get(d) || 0) + 1;
deckTimesMap.set(d, v);
}
//辗转相除法/欧几里得算法(计算两数的最大公约数)
// 如:48 与 18 的最大公约数
// 48 / 18 = 2 ... 12
// 18 / 12 = 1 ... 6
// 12 / 6 = 2 ... 0 此时值被整除,则 48 与 18 的最大公约数为 6
// 将未知数代入
//求 a 与 b 的 最大公约数(要求 a > b)
// a / b = 商 ... 余数,如果余数 !== 0 ,则 a = b, b = 余数
// a / b = 商 ... 余数,如果余数 !== 0 ,则 a = b, b = 余数
// ...
// a / b = 商 ... 余数,如果余数 === 0 ,则 a 与 b 的 最大公约数为 b
function gcd(a: number, b: number): number {
return b === 0 ? a : gcd(b, a % b);
}
const deckTimesList = [...deckTimesMap.values()];
//两两相算最大公约数,直到最后
const gcdValue = deckTimesList.reduce((pre, cur) => gcd(pre, cur));
return gcdValue >= 2;
}