题目描述:
给你一个由 不同 正整数组成的数组 nums
,请你返回满足 a * b = c * d
的元组 (a, b, c, d)
的数量。其中 a
、b
、c
和 d
都是 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,4,5)
(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
中的所有元素 互不相同
思路:
这个题目的大概的意思就是找四个不同的数,这四个数可以组成a*b=c*d的数量.
因为题目给的数组的长度是1000,直接暴力找4个数肯定是超时。
我们可以用一个数组num1把等式左边存下来,也就是把nums数组中任意两个数的乘积存下来,同时用一个map存下任意两个数的乘积的个数,时间复杂度是N^2。
接下来遍历num1,对于每两个数的乘积看是否还有另外两个数的乘积是一样的。记录数量就ok了。
首先,因为这四个数互不相等,我们应该先对nums进行去重,也就是将相同的元素去掉,这样对答案没有影响。
另外我们要考虑的就是,在遍历num1的时候,因为map记录了一次num1[i]本身,所以我们应该看此时的map[num1[i]]是否大于等于2,如果大于等于2,说明除了num1[i]还可以找到map[num1[i]]-1个两元乘积等于num1[i],此时答案ans+=map[num1[i]]-1,又因为此时的num1[i]已经作为等式左边计算过了,需要map[num1[i]]--。
比如 nums=[1,2,4,5,10]
那么任意两不同数之积num1=[2,4,5,10,8,10,20,20,40,50],同时用mp记录num1[i]的数量。
这里我们可以理解为每一个num1[i],都是等式的左边的二元数之积。
mp[10]=2,mp[20]=2(只看大于等于2的)
此时遍历num1,假如map[num1[i]]大于等于2,说明可以对于左边的num1[i],可以找到右边的二元数之积与之相等,然后再消除num[i]对后面元素作为等式左边值的影响,mp[num1[i]]--,不做么做的话,同一个四元积就重复了。
代码:
#define _CRT_SECURE_NO_WARNINGS 1 class Solution { public: int tupleSameProduct(vector<int>& nums) { vector<int> num1; sort(nums.begin(), nums.end()); nums.erase(unique(nums.begin(), nums.end()), nums.end());//排序去重 map<int, int> mp; for (int i = 0; i < nums.size(); i++) { for (int j = i + 1; j < nums.size(); j++) { num1.push_back(nums[i] * nums[j]); mp[nums[i] * nums[j]]++;//映射二元积的数量 } } int ans = 0; for (int i = 0; i < num1.size(); i++) { if (mp[num1[i]] >= 2) { ans += mp[num1[i]] - 1; mp[num1[i]]--;//消除影响 } } return ans * 8//每一个四积元组的顺序可以有八种 } };