目录
题目
给你一个由 不同 正整数组成的数组 nums
,请你返回满足 a * b = c * d
的元组 (a, b, c, d)
的数量。其中 a
、b
、c
和 d
都是 nums
中的元素,且 a != b != c != d
。
示例
输入:nums = [2,3,4,6] 输出:8 解释:存在 8 个满足题意的元组: (2,6,3,4) , (2,6,4,3) , (6,2,3,4) , (6,2,4,3) (3,4,2,6) , (4,3,2,6) , (3,4,6,2) , (4,3,6,2)
示例 2:
输入:nums = [1,2,4,5,10] 输出:16 解释:存在 16 个满足题意的元组: (1,10,2,5) , (1,10,5,2) , (10,1,2,5) , (10,1,5,2) (2,5,1,10) , (2,5,10,1) , (5,2,1,10) , (5,2,10,1) (2,10,4,5) , (2,10,5,4) , (10,2,4,5) , (10,2,4,5) (4,5,2,10) , (4,5,10,2) , (5,4,2,10) , (5,4,10,2)
题解
1. 这题主要就是组合数学,不同数之间的排列组合
2. 我们先来回忆一下我们高中学习的排列组合:
四个数,排列四个位置,一共有多少种排列方式?
我们可以看到,第一个位置有4种选法,第二个位置有3种选法,以此类推......
一共就是 4x3x2x1 = 24种
3. 好的,我们现在来看这道题,拿到这一题,我们第一个想法应该是枚举出每两个数字的和,然后进行统计,如果你这个和只有一个,那肯定无法构成a*b = c * d
4. 于是我们通过哈希表也就是字典的形式,键为总和,值为数量
5. 我们先来看样例:
[2,3,4,6]
我们可以看到,2*6 = 3*4
也就是12的值有2个,然后利用组合,我们有两组数字,要把这两组数字放在四个位置,并且要符合{a,b,c,d},于是要从这两组数据开始组合,就是C22,如果有n组数据,就是Cn2,从n个选2个出来进行组合
6. 然后我们分成两组,2 6 和3 4,这两组内的数据不能与其他组交换,不然值就不对了,保证a * b = c * d
7. 我们元组为{a,b,c,d},也就是分成a,b和c, d两个组,我们要从26和34两个组选一个去a,b组,然后剩下一个就定了,也就是C21
8. 去到那个组之后,内部还可以排序,也就是一个当a,一个当b,或者反过来,也就是有序的排列要用A22,然后有两个组,所以还要乘2
最后排列组合数就为:C21 * A22 * A22 = 8(也就是两组数字ab = cd,他们最后能够组合的数量)
9. 当然别忘了,前面是只有两组数据的和为12,也就是C22,如果我们有三组数相乘都等于同一个数的话,就需要从那三组数选两组出来,这样才满足a *b = c* d,也就是C32,最后就是C32 * C21 * A22 * A22
从而推导: n组就是 Cn2 * C21 * A22 * A22
简化一下就是Cn2 * 8
10。 最后将这些数相加就是最后的结果啦
代码
class Solution:
def tupleSameProduct(self, nums: List[int]) -> int:
dic = {}
l = len(nums)
# 枚举出所有数的和
for i in range(0,l-1):
for j in range(i,l):
if nums[i]!=nums[j]:
dic[nums[i] * nums[j]] = 0
for i in range(0,l-1):
for j in range(i,l):
if nums[i]!=nums[j]:
dic[nums[i] * nums[j]] += 1
num = 0
# 开始组合
for v in dic.values():
if v >= 2:
num += v*(v-1)//2 * 8 # 这个8其实就是C21 * A22 * A22,两组的排列组合数
return num
补充:
Cmn = m!/ (n! * (m-n)!)