📜  计算 Array 中乘积为任意正整数的 K 次方的对(1)

📅  最后修改于: 2023-12-03 14:57:26.597000             🧑  作者: Mango

计算 Array 中乘积为任意正整数的 K 次方的对

本任务的目标是给定一个整数数组 nums 和一个正整数 k,计算有多少对 (i,j) 满足 1 <= i < j <= nums.length,使得 nums[i]*nums[j] 的值的 k 次方是一个正整数。

思路

我们首先要明确一点,如果两个数的乘积是一个正整数,那么这两个数必须同时是正数或者同时是负数。因此,我们可以将数组 nums 按照正数和负数分开来考虑。

对于正数的情况,我们可以先将数组 nums 排序,然后使用双指针的方式寻找乘积为正整数的数对。

对于负数的情况,我们同样可以先将数组 nums 排序,并将负数排在数组的前面。接着对于每一个正数,在负数中查找与其乘积是正整数的数的个数,这可以使用二分查找来实现。

需要注意的是,如果 k 的值非常大,那么计算乘积的时候可能会出现溢出的情况。因此,我们可以考虑将乘积表示为质因数的形式,并计算每一个质因子的 k 次幂。这种方法可以避免溢出的问题。

代码实现
Python 代码
from typing import List
from bisect import bisect_left, bisect_right

def factorize(n: int) -> List[int]:
    # 将 n 分解成质因数的形式
    factors = []
    d = 2
    while d * d <= n:
        while (n % d) == 0:
            factors.append(d)
            n //= d
        d += 1
    if n > 1:
        factors.append(n)
    return factors

def countPairs(nums: List[int], k: int) -> int:
    n = len(nums)
    pos_nums = sorted([x for x in nums if x > 0])
    neg_nums = sorted([x for x in nums if x < 0])
    pos_count = 0
    for i in range(len(pos_nums)):
        j = bisect_left(pos_nums, (k-1) // (pos_nums[i]**k))   # 计算乘积的倒数的下取整
        pos_count += len(pos_nums[j:])
    neg_count = 0
    for i in range(len(neg_nums)):
        j = bisect_left(neg_nums, -(k-1) // abs(neg_nums[i]))  # 计算乘积的倒数的上取整
        neg_count += len(neg_nums[j:])
    ans = pos_count * (n - pos_count) + neg_count * (n - neg_count)
    for i in range(len(pos_nums)):
        factors = factorize(pos_nums[i])
        if len(factors) > 0 and max(factors) ** k <= (10**9):
            j = bisect_left(neg_nums, (10**9) // max(factors) ** k)
            ans += (len(neg_nums) - j) * (n - pos_count)
    return ans
Java 代码
import java.util.*;

class Solution {
    public List<Integer> factorize(int n) {
        // 将 n 分解成质因数的形式
        List<Integer> factors = new ArrayList<>();
        int d = 2;
        while (d * d <= n) {
            while (n % d == 0) {
                factors.add(d);
                n /= d;
            }
            d += 1;
        }
        if (n > 1) {
            factors.add(n);
        }
        return factors;
    }

    public int countPairs(int[] nums, int k) {
        int n = nums.length;
        int[] posNums = Arrays.stream(nums).filter(x -> x > 0).sorted().toArray();
        int[] negNums = Arrays.stream(nums).filter(x -> x < 0).sorted().toArray();
        int posCount = 0;
        for (int i = 0; i < posNums.length; i++) {
            int j = Arrays.binarySearch(posNums, (k-1) / power(posNums[i], k));
            if (j < 0) {
                j = -j-1;
            }
            posCount += posNums.length - j;
        }
        int negCount = 0;
        for (int i = 0; i < negNums.length; i++) {
            int j = Arrays.binarySearch(negNums, -(k-1) / Math.abs(negNums[i]));
            if (j < 0) {
                j = -j-1;
            }
            negCount += negNums.length - j;
        }
        int ans = posCount * (n - posCount) + negCount * (n - negCount);
        for (int i = 0; i < posNums.length; i++) {
            List<Integer> factors = factorize(posNums[i]);
            if (factors.size() > 0 && power(max(factors), k) <= 1e9) {
                int j = Arrays.binarySearch(negNums, (int) (1e9 / power(max(factors), k)));
                if (j < 0) {
                    j = -j-1;
                }
                ans += (negNums.length - j) * (n - posCount);
            }
        }
        return ans;
    }

    private int power(int x, int k) {
        int res = 1;
        while (k > 0) {
            if ((k & 1) != 0) {
                if (res > 1e9 / x) {
                    return -1;
                }
                res *= x;
            }
            if (k > 1 && x > 1e9 / x) {
                return -1;
            }
            x *= x;
            k >>= 1;
        }
        return res;
    }

    private int max(List<Integer> nums) {
        int res = 0;
        for (int num : nums) {
            res = Math.max(res, num);
        }
        return res;
    }
}
结语

该问题虽然涉及到一些数学知识,但是思路比较清晰,实现较为简单,主要考察对二分查找的掌握程度。对于用 Python 的程序员来说,可以使用 bisect 模块来简化二分查找;对于用 Java 的程序员来说,则可以使用 Arrays.binarySearch() 函数。