数的平方等于两数乘积的方法数

标签: 数组 哈希表 数学 双指针

难度: Medium

给你两个整数数组 nums1nums2 ,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):

  • 类型 1:三元组 (i, j, k) ,如果 nums1[i]2 == nums2[j] * nums2[k] 其中 0 <= i < nums1.length0 <= j < k < nums2.length
  • 类型 2:三元组 (i, j, k) ,如果 nums2[i]2 == nums1[j] * nums1[k] 其中 0 <= i < nums2.length0 <= j < k < nums1.length

示例 1:

输入:nums1 = [7,4], nums2 = [5,2,8,9]
输出:1
解释:类型 1:(1,1,2), nums1[1]^2 = nums2[1] * nums2[2] (4^2 = 2 * 8)

示例 2:

输入:nums1 = [1,1], nums2 = [1,1,1]
输出:9
解释:所有三元组都符合题目要求,因为 1^2 = 1 * 1
类型 1:(0,0,1), (0,0,2), (0,1,2), (1,0,1), (1,0,2), (1,1,2), nums1[i]^2 = nums2[j] * nums2[k]
类型 2:(0,0,1), (1,0,1), (2,0,1), nums2[i]^2 = nums1[j] * nums1[k]

示例 3:

输入:nums1 = [7,7,8,3], nums2 = [1,2,9,7]
输出:2
解释:有两个符合题目要求的三元组
类型 1:(3,0,2), nums1[3]^2 = nums2[0] * nums2[2]
类型 2:(3,0,1), nums2[3]^2 = nums1[0] * nums1[1]

示例 4:

输入:nums1 = [4,7,9,11,23], nums2 = [3,5,1024,12,18]
输出:0
解释:不存在符合题目要求的三元组

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 1 <= nums1[i], nums2[i] <= 10^5

Submission

运行时间: 48 ms

内存: 16.2 MB

class Solution:
    def numTriplets(self, nums1: List[int], nums2: List[int]) -> int:
        def get_count(nums1,nums2):
            for i in range(len(nums1)):
                nums1[i]*=nums1[i]
            ma1 = collections.defaultdict(int)
            for num in nums1:
                ma1[num]+=1
            res = 0
            ma = collections.defaultdict(int)
            for num in nums2:
                ma[num]+=1
            one_list = list(ma1.keys())
            key_list = list(ma.keys())
            for one in one_list:
                for two in key_list:
                    if one %two==0:
                        three = one//two
                        if three in ma:
                            if three==two:
                                res+=ma1[one]*((ma[three]*(ma[three]-1))//2)
                            elif three<two:
                                res+=ma1[one]*ma[three]*ma[two]
            return res
        nums3 = nums1[:]
        nums4 = nums2[:]
        return get_count(nums1,nums2) + get_count(nums4,nums3)

Explain

此题解采用了哈希表来统计两个数组中每个数的平方值和每个数出现的次数。首先,遍历第一个数组(nums1或nums2),计算每个数的平方,并用一个哈希表(ma1)记录每个平方值出现的次数。接着,用另一个哈希表(ma)记录第二个数组(nums2或nums1)中每个数出现的次数。然后,对于ma1中的每个键(即nums1中某数的平方),检查是否可以被nums2中任意两数的乘积得到。这是通过遍历ma的键来实现的:对于每个键,检查它是否能整除当前平方值,若能,则计算商是否也在ma中,从而确定是否存在这样的三元组。如果两个数相同,则需要特殊处理,因为从ma中选择两个相同的数有组合数种选择方式。最后,函数返回所有满足条件的三元组总数。整个过程针对两个数组分别执行一次,并将结果相加。

时间复杂度: O((n + m) + n*m)

空间复杂度: O(n + m)

class Solution:
    def numTriplets(self, nums1: List[int], nums2: List[int]) -> int:
        def get_count(nums1, nums2):
            # Squaring elements of nums1
            for i in range(len(nums1)):
                nums1[i] *= nums1[i]
            ma1 = collections.defaultdict(int)
            # Counting frequency of squared numbers in nums1
            for num in nums1:
                ma1[num] += 1
            res = 0
            ma = collections.defaultdict(int)
            # Counting frequency of numbers in nums2
            for num in nums2:
                ma[num] += 1
            one_list = list(ma1.keys())
            key_list = list(ma.keys())
            # Checking pairs of numbers in nums2 that can form the required products
            for one in one_list:
                for two in key_list:
                    if one % two == 0:
                        three = one // two
                        if three in ma:
                            if three == two:
                                res += ma1[one] * ((ma[three] * (ma[three] - 1)) // 2)
                            elif three < two:
                                res += ma1[one] * ma[three] * ma[two]
            return res
        nums3 = nums1[:]
        nums4 = nums2[:]
        # Checking both type 1 and type 2 triplets by swapping roles of nums1 and nums2
        return get_count(nums1, nums2) + get_count(nums4, nums3)

Explore

在这类问题中,需要频繁地查找和更新数字的频率以及检查特定值的存在。哈希表(或字典)提供了平均常数时间复杂度的查找、插入和更新操作,这使得它非常适合于需要频繁进行这些操作的场景。使用数组或列表可能会因为需要遍历整个结构来查找或更新数据而导致效率降低,尤其是在数据范围大或不连续的情况下。而树状数据结构如二叉搜索树或平衡树虽然可以提供对数时间复杂度的操作,但其实现复杂且在频繁更新操作时可能不如哈希表高效。

题解中没有明确说明如何处理nums2中包含0的情况,这是一个潜在的问题。在实际的编码实现中,如果nums2包含0,则在尝试进行除法运算时,程序应该进行检查以避免除以零的错误。具体实现时,可以在执行除法之前检查除数是否为0,并相应地跳过这种情况或处理为特殊情况。

题解中使用哈希表记录数字的频率,并在计算满足条件的组合时,特别处理了两个数字相同的情况。如果两个数字相同(即 `three == two`),则从ma中选择两个相同的数的方式是组合数 `(ma[three] * (ma[three] - 1)) / 2`,这自然满足了 `j < k` 的条件,因为它是从同一个数字中选择两个不同的实例。如果两个数字不同,则可以任意选择,因为哈希表并不记录元素的索引,而只关心数量,因此不需要额外操作来保证 `j < k`。

题解中的处理方式考虑了nums2中存在重复元素的情况,并正确计算了选择两个相同元素的组合数。如果所有nums2元素相同,那么`ma`哈希表中只有一个键值对,键是这个相同的数值,值是这个数值出现的次数。在这种情况下,计算组合数 `(ma[three] * (ma[three] - 1)) / 2` 仍然有效,可以正确计算出所有可能的组合方式。因此,题解已经考虑并处理了这种边界情况。