同积元组

标签: 数组 哈希表 计数

难度: Medium

给你一个由 不同 正整数组成的数组 nums ,请你返回满足 a * b = c * d 的元组 (a, b, c, d) 的数量。其中 abcd 都是 nums 中的元素,且 a != b != c != d

示例 1:

输入: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,5,4)
(4,5,2,10) , (4,5,10,2) , (5,4,2,10) , (5,4,10,2)

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 104
  • nums 中的所有元素 互不相同

Submission

运行时间: 277 ms

内存: 54.0 MB

class Solution:
    def tupleSameProduct(self, nums: List[int]) -> int:
        nums.sort()
        result = 0
        n = len(nums)
        chengji = []
        for i in range(n):
            for j in range(i+1,n):
                chengji.append(nums[i]*nums[j])
        a = Counter(chengji)
        def C(n):
            return n*(n-1)//2
        for value in a.values():
            if value>1:
                result+=C(value)
            else:
                continue
        return result*8

Explain

这个题解利用了哈希表来统计每一对乘积的出现次数。首先,对数组进行排序,然后使用两层循环遍历所有可能的两数乘积,并将这些乘积存储到一个列表中。之后,利用Counter统计列表中每个乘积出现的次数。对于每个乘积出现次数大于1的情况,计算可以由这些乘积形成的合法元组的数量,使用组合数的计算方法 C(n, 2) = n*(n-1)/2 来计算能够从中选取两对数字的方式数。最后,由于每个四元组可以以8种不同的方式排列(因为每对乘积可以交换位置,且两对乘积间也可以交换),所以将结果乘以8返回。

时间复杂度: O(n^2)

空间复杂度: O(n^2)

class Solution:
    def tupleSameProduct(self, nums: List[int]) -> int:
        nums.sort()  # 对数组进行排序
        result = 0
        n = len(nums)
        chengji = []
        for i in range(n):
            for j in range(i+1,n):
                chengji.append(nums[i]*nums[j])  # 计算并存储所有可能的两数乘积
        a = Counter(chengji)  # 使用Counter计算每个乘积出现的次数
        def C(n):
            return n*(n-1)//2  # 定义组合数计算函数
        for value in a.values():
            if value>1:
                result+=C(value)  # 对于每个出现次数大于1的乘积,计算可以形成的元组数
            else:
                continue
        return result*8  # 由于每个元组可以有8种排列方式,所以最后结果乘以8

Explore

对数组进行排序主要是为了优化算法的效率和简化逻辑。排序后,可以保证在双层循环中,当固定第一个数时,后面的数总是递增的,这样可以有效避免重复计算相同的乘积组合。例如,对于未排序的数组可能出现多次相同的乘积计算,而排序之后,可以确保每个乘积只被计算一次。此外,排序有助于后续操作如二分查找等,虽然在这个特定算法中未直接使用。总的来说,排序不影响算法的正确性,但可以提高算法的执行效率和减少冗余操作。

题目要求找出可以形成同积四元组的组合,每个四元组包含两对乘积相等的数对。如果一个乘积在数组中只出现一次,那么它不可能与其他数对形成两对乘积相同的组合。因此,只有当一个乘积至少出现两次时,我们才能从中选择两对数对来形成一个有效的四元组。这是为什么算法中只考虑乘积出现次数大于1的情况,因为出现一次的乘积无法满足题目要求形成四元组的条件。

每个有效的四元组由两对乘积相等的数对组成。考虑两对数对 (a, b) 和 (c, d),其中 a*b = c*d。这两对数对可以在各自内部交换位置,即 (a, b) 可以变为 (b, a),同样 (c, d) 可以变为 (d, c)。这给出了每对内部的两种可能,总共是 2*2 = 4 种内部组合。此外,两对数对之间也可以交换位置,即 (a, b, c, d) 可以变为 (c, d, a, b)。因此,每种内部组合又可以通过两对之间的交换产生额外的组合,所以总的组合数为 4*2 = 8。这就是每个四元组有8种不同排列方式的来源。