leetcode
leetcode 2401 ~ 2450
限制条件下元素之间的最小绝对差

限制条件下元素之间的最小绝对差

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and an integer x.

Find the minimum absolute difference between two elements in the array that are at least x indices apart.

In other words, find two indices i and j such that abs(i - j) >= x and abs(nums[i] - nums[j]) is minimized.

Return an integer denoting the minimum absolute difference between two elements that are at least x indices apart.

 

Example 1:

Input: nums = [4,3,2,4], x = 2
Output: 0
Explanation: We can select nums[0] = 4 and nums[3] = 4. 
They are at least 2 indices apart, and their absolute difference is the minimum, 0. 
It can be shown that 0 is the optimal answer.

Example 2:

Input: nums = [5,3,2,10,15], x = 1
Output: 1
Explanation: We can select nums[1] = 3 and nums[2] = 2.
They are at least 1 index apart, and their absolute difference is the minimum, 1.
It can be shown that 1 is the optimal answer.

Example 3:

Input: nums = [1,2,3,4], x = 3
Output: 3
Explanation: We can select nums[0] = 1 and nums[3] = 4.
They are at least 3 indices apart, and their absolute difference is the minimum, 3.
It can be shown that 3 is the optimal answer.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 0 <= x < nums.length

代码结果

运行时间: 506 ms, 内存: 31.4 MB


/*
 * 思路:
 * 1. 使用IntStream遍历所有可能的下标对(i, j),其中i从0到nums.length - x - 1,j从i + x到nums.length。
 * 2. 计算每一对(i, j)的差值绝对值,并将其收集到一个流中。
 * 3. 使用min()方法找到流中的最小值。
 */
import java.util.stream.IntStream;
public class Solution {
    public int minAbsoluteDifference(int[] nums, int x) {
        return IntStream.range(0, nums.length - x)
                        .flatMap(i -> IntStream.range(i + x, nums.length)
                                               .map(j -> Math.abs(nums[i] - nums[j])))
                        .min()
                        .orElse(Integer.MAX_VALUE);
    }
}

解释

方法:

这道题目的基本思路是利用滑动窗口和二分查找。首先,定义一个列表 `pre` 用以存储滑动窗口中的元素(窗口大小为 `x`),并且保持这个列表有序。遍历数组 `nums` 从下标 `x` 开始,每次将下标 `i-x` 的元素插入到 `pre` 中的适当位置以保持列表的有序性。对于每个 `i`,我们使用二分查找确定 `nums[i]` 在 `pre` 中的位置,然后计算 `nums[i]` 和它前后元素的差的绝对值,以此来找出最小的差值。这个方法通过动态维护一个有序数组来快速计算任意元素与其距离至少为 `x` 的元素的最小绝对差。

时间复杂度:

O((n-x) log x)

空间复杂度:

O(x)

代码细节讲解

🦆
为什么在实现中选择使用滑动窗口和二分查找的组合来解决这个问题?是否有其他数据结构可以达到相同或更优的效率?
滑动窗口和二分查找的组合在这个问题中被使用是因为它们可以有效地维护和查询有序的数据集合。滑动窗口允许我们在遍历数组时动态地更新窗口内元素,保持窗口大小固定,而二分查找则提供了快速查找和插入元素的能力,使得每次操作的时间复杂度为O(log x)。尽管这种方法有效,但使用平衡二叉搜索树(如AVL树或红黑树)可能会提供相同甚至更好的效率,因为它们在插入、删除和查找操作中也能保持O(log x)的时间复杂度,并且更直接地支持动态数据的快速访问和更新。
🦆
在题解中提到的`pre.insert(bisect_left(pre, nums[i-x]), nums[i-x])`操作,如何确保插入操作不会导致性能瓶颈,特别是在窗口大小x较大的情况下?
在使用`pre.insert(bisect_left(pre, nums[i-x]), nums[i-x])`操作时,虽然二分查找能以O(log x)的时间复杂度找到插入位置,但实际的插入操作可能需要O(x)的时间复杂度,因为它涉及到数组元素的移动。这确实可能成为性能瓶颈特别是当窗口x较大时。为了避免这种情况,可以考虑使用数据结构如平衡二叉搜索树,它在维护有序元素集合时,插入和删除操作都可以保持O(log x)的时间复杂度,这样可以更有效地处理大量元素的动态插入和删除。
🦆
题解提到了初始化答案为`abs(nums[0] - nums[-1])`,这种初始化方式是否总是有效,或者是否存在更合理的初始化方法?
初始化答案为`abs(nums[0] - nums[-1])`是一种假设性的初始条件,可能并不总是合理,因为它只考虑了数组的第一个元素和最后一个元素的差值,而实际上最小绝对差可能出现在数组的任何两个距离至少为x的元素之间。更合理的初始化方法是设置一个非常大的数(如正无穷),这样可以确保在初始状态不会错误地限制了答案的下界,使算法能够正确地更新最小差值。
🦆
题解中遍历数组的起始点是x,结束点是n,为什么选择从x开始而不是从0开始遍历?
遍历从x开始而不是从0开始,是因为题目要求比较的是任意两个距离至少为x的元素之间的差值。如果从0开始遍历,那么在下标小于x的情况下,无法找到距离至少为x的另一个元素来进行比较。因此,从x开始遍历可以直接跳过那些无法找到有效比较目标的初始元素,这样做既可以节省计算时间也符合题目要求。

相关问题