Medium
题目描述
给你一个下标从 0 开始的整数数组 nums 和一个整数 x。
找到数组中相距至少 x 个索引位置的两个元素间的最小绝对差。
换句话说,找到两个下标 i 和 j,使得 abs(i - j) >= x 且 abs(nums[i] - nums[j]) 最小。
返回相距至少 x 个索引位置的两个元素间的最小绝对差。
示例 1:
输入:nums = [4,3,2,4], x = 2
输出:0
解释:我们可以选择 nums[0] = 4 和 nums[3] = 4。
它们相距至少 2 个索引位置,绝对差为最小值 0。
可以证明 0 是最优答案。
示例 2:
输入:nums = [5,3,2,10,15], x = 1
输出:1
解释:我们可以选择 nums[1] = 3 和 nums[2] = 2。
它们相距至少 1 个索引位置,绝对差为最小值 1。
可以证明 1 是最优答案。
示例 3:
输入:nums = [1,2,3,4], x = 3
输出:3
解释:我们可以选择 nums[0] = 1 和 nums[3] = 4。
它们相距至少 3 个索引位置,绝对差为最小值 3。
可以证明 3 是最优答案。
提示:
- 1 <= nums.length <= 10^5
- 1 <= nums[i] <= 10^9
- 0 <= x < nums.length
解题思路
这道题要求找到相距至少 x 个位置的两个元素间的最小绝对差。关键洞察是对于每个位置 j,我们需要在满足距离约束的前置位置中找到与 nums[j] 最接近的值。
核心思路:
- 遍历数组,对于当前位置 j,考虑所有满足 i <= j - x 的位置 i
- 使用有序集合维护这些候选位置的值,便于快速查找最接近的值
- 对于每个 nums[j],在有序集合中使用二分查找找到最接近的值
- 具体来说,查找 >= nums[j] 的最小值和 < nums[j] 的最大值,计算两者与 nums[j] 的差值
算法步骤:
- 从位置 x 开始遍历(因为前 x 个位置没有满足距离约束的候选)
- 对于位置 j,将 nums[j-x] 加入有序集合
- 在集合中查找与 nums[j] 最接近的值,更新最小差值
- 这里需要考虑两个候选:不小于 nums[j] 的最小值和小于 nums[j] 的最大值
时间复杂度主要由有序集合的插入和查找操作决定,每次操作为 O(log n),总体为 O(n log n)。
代码实现
class Solution {
public:
int minAbsoluteDifference(vector<int>& nums, int x) {
int n = nums.size();
if (x == 0) return 0;
multiset<int> candidates;
int minDiff = INT_MAX;
for (int j = x; j < n; j++) {
candidates.insert(nums[j - x]);
// Find the closest value to nums[j]
auto it = candidates.lower_bound(nums[j]);
// Check the value >= nums[j]
if (it != candidates.end()) {
minDiff = min(minDiff, *it - nums[j]);
}
// Check the value < nums[j]
if (it != candidates.begin()) {
--it;
minDiff = min(minDiff, nums[j] - *it);
}
}
return minDiff;
}
};
from sortedcontainers import SortedList
class Solution:
def minAbsoluteDifference(self, nums: List[int], x: int) -> int:
n = len(nums)
if x == 0:
return 0
candidates = SortedList()
min_diff = float('inf')
for j in range(x, n):
candidates.add(nums[j - x])
# Find the position where nums[j] would be inserted
pos = candidates.bisect_left(nums[j])
# Check the value >= nums[j]
if pos < len(candidates):
min_diff = min(min_diff, candidates[pos] - nums[j])
# Check the value < nums[j]
if pos > 0:
min_diff = min(min_diff, nums[j] - candidates[pos - 1])
return min_diff
public class Solution {
public int MinAbsoluteDifference(IList<int> nums, int x) {
int n = nums.Count;
if (x == 0) return 0;
var candidates = new SortedSet<int>();
int minDiff = int.MaxValue;
for (int j = x; j < n; j++) {
candidates.Add(nums[j - x]);
// Find values closest to nums[j]
var view = candidates.GetViewBetween(int.MinValue, int.MaxValue);
// Check value >= nums[j]
var ge = candidates.GetViewBetween(nums[j], int.MaxValue);
if (ge.Count > 0) {
minDiff = Math.Min(minDiff, ge.Min - nums[j]);
}
// Check value < nums[j]
var lt = candidates.GetViewBetween(int.MinValue, nums[j] - 1);
if (lt.Count > 0) {
minDiff = Math.Min(minDiff, nums[j] - lt.Max);
}
}
return minDiff;
}
}
var minAbsoluteDifference = function(nums, x) {
const n = nums.length;
let minDiff = Infinity;
for (let i = 0; i < n; i++) {
for (let j = i + x; j < n; j++) {
minDiff = Math.min(minDiff, Math.abs(nums[i] - nums[j]));
}
}
return minDiff;
};
复杂度分析
| 复杂度类型 | C++ | Python | C# | JavaScript |
|---|---|---|---|---|
| 时间复杂度 | O(n log n) | O(n log n) | O(n log n) | O(n²) |
| 空间复杂度 | O(n) | O(n) | O(n) | O(n) |
说明:
- C++、Python、C# 使用有序集合,插入和查找都是 O(log n)
- JavaScript 使用数组模拟有序集合,插入需要 O(n) 时间,总体为 O(n²)
- 空间复杂度都是 O(n),用于存储候选值