leetcode
leetcode 2651 ~ 2700
同积元组

同积元组

难度:

标签:

题目描述

Given an array nums of distinct positive integers, return the number of tuples (a, b, c, d) such that a * b = c * d where a, b, c, and d are elements of nums, and a != b != c != d.

 

Example 1:

Input: nums = [2,3,4,6]
Output: 8
Explanation: There are 8 valid tuples:
(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)

Example 2:

Input: nums = [1,2,4,5,10]
Output: 16
Explanation: There are 16 valid tuples:
(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)

 

Constraints:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 104
  • All elements in nums are distinct.

代码结果

运行时间: 277 ms, 内存: 54.0 MB


/*
 * 思路:
 * 1. 使用Map来存储每个乘积以及对应的数对的个数。
 * 2. 使用流处理对数组进行两两组合,并计算其乘积。
 * 3. 如果Map中已经存在该乘积,则计数增加。
 */
import java.util.*;
import java.util.stream.*;

public class Solution {
    public int tupleSameProduct(int[] nums) {
        Map<Integer, Integer> productCount = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                int product = nums[i] * nums[j];
                productCount.put(product, productCount.getOrDefault(product, 0) + 1);
            }
        }
        return productCount.values().stream()
                .mapToInt(count -> count * (count - 1) * 4)
                .sum();
    }
}

解释

方法:

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

时间复杂度:

O(n^2)

空间复杂度:

O(n^2)

代码细节讲解

🦆
为什么在计算乘积时选择对数组进行排序?这一步是否对算法的正确性或效率有特定的影响?
对数组进行排序主要是为了优化算法的效率和简化逻辑。排序后,可以保证在双层循环中,当固定第一个数时,后面的数总是递增的,这样可以有效避免重复计算相同的乘积组合。例如,对于未排序的数组可能出现多次相同的乘积计算,而排序之后,可以确保每个乘积只被计算一次。此外,排序有助于后续操作如二分查找等,虽然在这个特定算法中未直接使用。总的来说,排序不影响算法的正确性,但可以提高算法的执行效率和减少冗余操作。
🦆
在实现中,使用Counter统计乘积的出现次数后,只有当一个乘积的出现次数大于1时才进一步计算元组数。请问为什么乘积出现一次的情况不需要被计算?
题目要求找出可以形成同积四元组的组合,每个四元组包含两对乘积相等的数对。如果一个乘积在数组中只出现一次,那么它不可能与其他数对形成两对乘积相同的组合。因此,只有当一个乘积至少出现两次时,我们才能从中选择两对数对来形成一个有效的四元组。这是为什么算法中只考虑乘积出现次数大于1的情况,因为出现一次的乘积无法满足题目要求形成四元组的条件。
🦆
题解中提到`每个四元组可以以8种不同的方式排列`,能否详细解释这8种排列是如何得到的?
每个有效的四元组由两对乘积相等的数对组成。考虑两对数对 (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种不同排列方式的来源。

相关问题