哈希表题目:数的平方等于两数乘积的方法数

题目

标题和出处

标题:数的平方等于两数乘积的方法数

出处:1577. 数的平方等于两数乘积的方法数

难度

5 级

题目描述

要求

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

  • 类型 1 \texttt{1} 1:三元组 (i,   j,   k) \texttt{(i, j, k)} (i, j, k),如果 nums1[i] 2 = nums2[j] × nums2[k] \texttt{nums1[i]}^\texttt{2} = \texttt{nums2[j]} \times \texttt{nums2[k]} nums1[i]2=nums2[j]×nums2[k],其中 0 ≤ i < nums1.length \texttt{0} \le \texttt{i} < \texttt{nums1.length} 0i<nums1.length 0 ≤ j < k < nums2.length \texttt{0} \le \texttt{j} < \texttt{k} < \texttt{nums2.length} 0j<k<nums2.length
  • 类型 2 \texttt{2} 2:三元组 (i,   j,   k) \texttt{(i, j, k)} (i, j, k),如果 nums2[i] 2 = nums1[j] × nums1[k] \texttt{nums2[i]}^\texttt{2} = \texttt{nums1[j]} \times \texttt{nums1[k]} nums2[i]2=nums1[j]×nums1[k],其中 0 ≤ i < nums2.length \texttt{0} \le \texttt{i} < \texttt{nums2.length} 0i<nums2.length 0 ≤ j < k < nums1.length \texttt{0} \le \texttt{j} < \texttt{k} < \texttt{nums1.length} 0j<k<nums1.length

示例

示例 1:

输入: nums1   =   [7,4],   nums2   =   [5,2,8,9] \texttt{nums1 = [7,4], nums2 = [5,2,8,9]} nums1 = [7,4], nums2 = [5,2,8,9]
输出: 1 \texttt{1} 1
解释:类型 1 \texttt{1} 1 (1,1,2) \texttt{(1,1,2)} (1,1,2) nums1[1] 2 = nums2[1] × nums2[2] \texttt{nums1[1]}^\texttt{2} = \texttt{nums2[1]} \times \texttt{nums2[2]} nums1[1]2=nums2[1]×nums2[2] 4 2 = 2 × 8 \texttt{4}^\texttt{2} = \texttt{2} \times \texttt{8} 42=2×8)。

示例 2:

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

示例 3:

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

示例 4:

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

数据范围

  • 1 ≤ nums1.length,   nums2.length ≤ 1000 \texttt{1} \le \texttt{nums1.length, nums2.length} \le \texttt{1000} 1nums1.length, nums2.length1000
  • 1 ≤ nums1[i],   nums2[i] ≤ 10 5 \texttt{1} \le \texttt{nums1[i], nums2[i]} \le \texttt{10}^\texttt{5} 1nums1[i], nums2[i]105

解法

思路和算法

( i , j , k ) (i, j, k) (i,j,k) 表示符合题目要求的三元组。

如果 ( i , j , k ) (i, j, k) (i,j,k) 是类型 1 1 1 的三元组,则令 x = nums 1 [ i ] x = \textit{nums}_1[i] x=nums1[i] y = nums 2 [ j ] y = \textit{nums}_2[j] y=nums2[j] z = nums 2 [ k ] z = \textit{nums}_2[k] z=nums2[k],有 x 2 = y × z x^2 = y \times z x2=y×z。如果 ( i , j , k ) (i, j, k) (i,j,k) 是类型 2 2 2 的三元组,则令 x = nums 2 [ i ] x = \textit{nums}_2[i] x=nums2[i] y = nums 1 [ j ] y = \textit{nums}_1[j] y=nums1[j] z = nums 1 [ k ] z = \textit{nums}_1[k] z=nums1[k],有 x 2 = y × z x^2 = y \times z x2=y×z

为了计算符合题目要求的三元组的数目,需要分别计算类型 1 1 1 和类型 2 2 2 的三元组的数目。假设数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2 的长度分别是 m m m n n n。如果暴力统计符合题目要求的三元组,则统计类型 1 1 1 的三元组需要 O ( m n 2 ) O(mn^2) O(mn2) 的时间,统计类型 2 2 2 的三元组需要 O ( n m 2 ) O(nm^2) O(nm2) 的时间,总时间复杂度是 O ( m n ( m + n ) ) O(mn(m + n)) O(mn(m+n)),会超出时间限制,因此需要优化。

暴力方法的时间复杂度过高是因为相同的元素被重复计算。为了降低时间复杂度,应该避免重复计算。可以使用哈希表记录数组中的元素和每个元素的出现次数。

首先遍历数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2,分别用两个哈希表记录两个数组中每个元素的出现次数,用 set 1 \textit{set}_1 set1 set 2 \textit{set}_2 set2 分别表示两个数组的元素集合,然后计算两种类型的三元组的数目。两种类型的三元组的数目的计算方式大致相同。

计算类型 1 1 1 的三元组的数目的方法如下:对于集合 set 1 \textit{set}_1 set1 中的每个元素 x x x,遍历集合 set 2 \textit{set}_2 set2 中的每个元素 y y y,如果集合 set 2 \textit{set}_2 set2 中存在元素 z z z 满足 x 2 = y × z x^2 = y \times z x2=y×z y y y z z z 在数组 nums 2 \textit{nums}_2 nums2 中对应的下标不同,则 x x x y y y z z z 这三个元素组成一个类型 1 1 1 的三元组。记 x x x 在数组 nums 1 \textit{nums}_1 nums1 中的出现次数为 xCount \textit{xCount} xCount y y y z z z 在数组 nums 2 \textit{nums}_2 nums2 中的出现次数分别为 yCount \textit{yCount} yCount zCount \textit{zCount} zCount,则可以根据出现次数计算该三元组的出现次数。为了避免重复计算,只考虑 y ≤ z y \le z yz 的情况。该三元组的出现次数计算如下:

  • 如果 y = z y = z y=z,则该三元组的出现次数是 xCount × yCount × ( yCount − 1 ) 2 \textit{xCount} \times \dfrac{\textit{yCount} \times (\textit{yCount} - 1)}{2} xCount×2yCount×(yCount1)

  • 如果 y < z y < z y<z,则该三元组的出现次数是 xCount × yCount × zCount \textit{xCount} \times \textit{yCount} \times \textit{zCount} xCount×yCount×zCount

计算类型 2 2 2 的三元组的数目的方法大致相同,区别是在集合 set 2 \textit{set}_2 set2 中遍历元素 x x x,在集合 set 1 \textit{set}_1 set1 中遍历元素 y y y 并寻找元素 z z z

得到类型 1 1 1 和类型 2 2 2 的三元组的数目之后,即可得到符合题目要求的三元组的数目。

代码

class Solution {
    public int numTriplets(int[] nums1, int[] nums2) {
        Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
        Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
        for (int num : nums1) {
            map1.put(num, map1.getOrDefault(num, 0) + 1);
        }
        for (int num : nums2) {
            map2.put(num, map2.getOrDefault(num, 0) + 1);
        }
        return numTriplets(map1, map2) + numTriplets(map2, map1);
    }

    public int numTriplets(Map<Integer, Integer> map1, Map<Integer, Integer> map2) {
        int triplets = 0;
        Set<Integer> set1 = map1.keySet();
        Set<Integer> set2 = map2.keySet();
        for (int x : set1) {
            long square = (long) x * x;
            int xCount = map1.get(x);
            for (int y : set2) {
                if (square % y == 0 && square / y <= Integer.MAX_VALUE) {
                    int z = (int) (square / y);
                    if (!map2.containsKey(z)) {
                        continue;
                    }
                    int yCount = map2.get(y);
                    if (y == z) {
                        triplets += xCount * (yCount * (yCount - 1) / 2);
                    } else if (y < z) {
                        int zCount = map2.get(z);
                        triplets += xCount * yCount * zCount;
                    }
                }
            }
        }
        return triplets;
    }
}

复杂度分析

  • 时间复杂度: O ( m n ) O(mn) O(mn),其中 m m m n n n 分别是数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2 的长度。遍历数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2 并使用哈希表记录两个数组中的每个元素的出现次数需要 O ( m + n ) O(m + n) O(m+n) 的时间,计算类型 1 1 1 和类型 2 2 2 的三元组的数目各需要 O ( m n ) O(mn) O(mn) 的时间,因此总时间复杂度是 O ( m n ) O(mn) O(mn)

  • 空间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m n n n 分别是数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2 的长度。需要使用两个哈希表分别记录数组 nums 1 \textit{nums}_1 nums1 nums 2 \textit{nums}_2 nums2 中的每个元素的出现次数,两个哈希表的空间分别是 O ( m ) O(m) O(m) O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值