leetcode
leetcode 2451 ~ 2500
找出满足差值条件的下标 II

找出满足差值条件的下标 II

难度:

标签:

题目描述

You are given a 0-indexed integer array nums having length n, an integer indexDifference, and an integer valueDifference.

Your task is to find two indices i and j, both in the range [0, n - 1], that satisfy the following conditions:

  • abs(i - j) >= indexDifference, and
  • abs(nums[i] - nums[j]) >= valueDifference

Return an integer array answer, where answer = [i, j] if there are two such indices, and answer = [-1, -1] otherwise. If there are multiple choices for the two indices, return any of them.

Note: i and j may be equal.

 

Example 1:

Input: nums = [5,1,4,1], indexDifference = 2, valueDifference = 4
Output: [0,3]
Explanation: In this example, i = 0 and j = 3 can be selected.
abs(0 - 3) >= 2 and abs(nums[0] - nums[3]) >= 4.
Hence, a valid answer is [0,3].
[3,0] is also a valid answer.

Example 2:

Input: nums = [2,1], indexDifference = 0, valueDifference = 0
Output: [0,0]
Explanation: In this example, i = 0 and j = 0 can be selected.
abs(0 - 0) >= 0 and abs(nums[0] - nums[0]) >= 0.
Hence, a valid answer is [0,0].
Other valid answers are [0,1], [1,0], and [1,1].

Example 3:

Input: nums = [1,2,3], indexDifference = 2, valueDifference = 4
Output: [-1,-1]
Explanation: In this example, it can be shown that it is impossible to find two indices that satisfy both conditions.
Hence, [-1,-1] is returned.

 

Constraints:

  • 1 <= n == nums.length <= 105
  • 0 <= nums[i] <= 109
  • 0 <= indexDifference <= 105
  • 0 <= valueDifference <= 109

代码结果

运行时间: 60 ms, 内存: 30.5 MB


/*
 * 题目思路:
 * 1. 使用 Java Stream 进行数组的遍历,使用两层流处理,外层流为 i,内层流为 j。
 * 2. 对于每个 i 和 j,检查是否满足 abs(i - j) >= indexDifference 和 abs(nums[i] - nums[j]) >= valueDifference 的条件。
 * 3. 如果满足条件,则返回 [i, j]。
 * 4. 如果没有找到满足条件的对,返回 [-1, -1]。
 */
import java.util.stream.IntStream;
public class Solution {
    public int[] findIndices(int[] nums, int indexDifference, int valueDifference) {
        int n = nums.length;
        return IntStream.range(0, n)
                .flatMap(i -> IntStream.range(0, n)
                        .filter(j -> Math.abs(i - j) >= indexDifference && Math.abs(nums[i] - nums[j]) >= valueDifference)
                        .mapToObj(j -> new int[]{i, j}))
                .findFirst()
                .orElse(new int[]{-1, -1});
    }
}

解释

方法:

此题解采用了滑动窗口的方法来寻找满足条件的下标i和j。首先定义两个变量mxi和mni,分别用于记录当前窗口中最大和最小元素的下标。窗口的大小由indexDifference参数确定,即窗口内任两点的下标差至少为indexDifference。然后遍历数组,对于每个元素nums[j],计算其与indexDifference之前的元素的最大值和最小值的差。如果任一差值满足valueDifference,则返回对应的下标。如果遍历完成后没有找到满足条件的下标对,则返回[-1, -1]。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到使用滑动窗口的大小由`indexDifference`参数决定,具体是如何应用这个参数来设置窗口大小的?
在题解中,滑动窗口的大小实际上是通过`indexDifference`来间接确定的。窗口内的元素数量并不是直接等于`indexDifference`,而是通过确保`i`和`j`之间的索引差至少为`indexDifference`来维持窗口的逻辑。这意味着窗口的实际宽度(即包含的元素数量)可以根据数组的遍历动态调整,但始终保证任何被比较的两个元素的下标差不小于`indexDifference`。这种设置使得算法能够在遍历数组时,始终保持一个满足条件的动态窗口,用于检查是否有两个元素满足给定的值差条件。
🦆
在更新最大和最小下标`mxi`和`mni`时,为什么只考虑了当前窗口开始下标`i`的元素,而没有遍历整个窗口来确定最大或最小值?
题解采用了一种贪心策略,只在每次迭代时检查新加入窗口的元素(即`i`位置的元素),而不重新遍历整个窗口。这种方法假设在之前的步骤中,窗口内的最大值和最小值已经被正确更新。因此,只需考虑新元素是否会影响当前的最大或最小记录即可。这样可以大幅减少计算量,提高效率。然而,这种方法在实际代码实现中存在逻辑漏洞,因为当最大值或最小值离开窗口时应重新计算窗口内的最大或最小值,而题解中的实现并未处理这一点。
🦆
题解中的滑动窗口策略似乎没有处理窗口内最大或最小值下标失效的情况(即当这些下标超出当前考虑的窗口时)。这种情况该如何处理?
正确地处理窗口内最大值或最小值下标失效的问题是滑动窗口算法的关键部分。在题解中的实现方式中,如果最大或最小值的下标`mxi`或`mni`超过了当前窗口的边界,应当重新扫描当前窗口以确定新的最大或最小值。更高效的方法是使用数据结构如双端队列(Deque),它可以在每次窗口滑动时高效地添加新元素并移除旧元素,同时维护窗口内的最大或最小值的下标。这样可以在每次窗口更新时保持常数时间复杂度的更新操作,而不需要重新扫描整个窗口。

相关问题