leetcode
leetcode 2301 ~ 2350
美数对

美数对

难度:

标签:

题目描述

代码结果

运行时间: 146 ms, 内存: 36.7 MB


/*
 * Leetcode 2613: 美数对
 * 题目思路:
 * 给定一个整数数组 nums 和一个整数 k,求满足以下条件的元素对 (i, j) 的数量:
 * 1. 0 <= i < j < nums.length
 * 2. nums[i] == nums[j]
 * 3. (i * j) % k == 0
 */

import java.util.stream.IntStream;

public class BeautifulPairsStream {
    public int countBeautifulPairs(int[] nums, int k) {
        return (int) IntStream.range(0, nums.length)
            .flatMap(i -> IntStream.range(i + 1, nums.length)
                .filter(j -> nums[i] == nums[j] && (i * j) % k == 0))
            .count();
    }

    public static void main(String[] args) {
        BeautifulPairsStream bp = new BeautifulPairsStream();
        int[] nums = {1, 2, 3, 1, 1, 3};
        int k = 2;
        System.out.println(bp.countBeautifulPairs(nums, k)); // Output: 2
    }
}

解释

方法:

该题解使用分治法和归并排序的思想来解决问题。首先将所有点按照 x 坐标排序,然后递归地将点集划分为左右两个子集,分别求解子问题。在合并时,对于横跨左右子集的点对,可以通过维护一个纵坐标有序的点集,在一定范围内枚举所有可能的点对,更新全局最优解。最后返回距离最小的一对点的下标。

时间复杂度:

O(nlog^2n)

空间复杂度:

O(nlogn)

代码细节讲解

🦆
在分治法中,为什么选择以x坐标来排序并划分点集,而不是选择y坐标或其他属性?
在分治法中,选择以x坐标来排序并划分点集是为了简化问题的复杂性并高效地处理距离计算。这种方法基于最近点对问题的典型解法,其中按照x坐标排序可以帮助我们在递归分治过程中容易地将点集划分为相对独立的左右两部分。这样做的好处是在合并步骤中,可以有效地限制需要考虑的点对的数量,因为横跨左右子集的点对的潜在最小距离将受到左右子集内部点对距离的影响。如果我们选择排序和分割的其他属性,比如y坐标,虽然理论上可行,但在处理跨越分界线的点对时可能需要考虑更多的点,这增加了问题的复杂度。
🦆
递归处理过程中,当点集只有一个点时返回的是 inf, -1, -1,这样的返回值是如何在上层递归中被处理的?
在递归处理过程中,当点集只剩下一个点时,显然无法形成点对,因此返回的距离是无穷大(inf),以及无效的点对下标(-1, -1)。这种返回值在上层递归中用于判断和处理。当这样的返回值被合并到上层递归中时,任何有效的点对(即距离不是无穷大的点对)都将比这个返回值更优,因此这个返回值不会影响到最终的最小距离的计算。上层递归会忽略这个无效的点对,只考虑有效的点对进行距离比较和最小值更新。
🦆
对于横跨左右子集的点对,为什么确定纵坐标的差值不超过d1就可以停止枚举?这样是否可能漏掉某些有效的点对?
在处理横跨左右子集的点对时,限制纵坐标的差值不超过已知的最小距离d1是基于距离的上界考虑。这种方法基于一个观察:如果两点的纵坐标之差大于d1,则无论它们的横坐标如何,它们之间的曼哈顿距离必然大于d1。因此,这种情况下,这对点不可能成为新的最近点对。虽然这种方法在理论上可能看起来有风险,但由于曼哈顿距离的定义(两点间距离等于它们在每个坐标维度上差的绝对值之和),这种策略实际上是安全的,并不会漏掉任何可能的最近点对。

相关问题