3488.距离最小相等元素查询

目标

给你一个 环形 数组 nums 和一个数组 queries 。

对于每个查询 i ,你需要找到以下内容:

  • 数组 nums 中下标 queries[i] 处的元素与 任意 其他下标 j(满足 nums[j] == nums[queries[i]])之间的 最小 距离。如果不存在这样的下标 j,则该查询的结果为 -1 。

返回一个数组 answer,其大小与 queries 相同,其中 answer[i] 表示查询i的结果。

示例 1:

输入: nums = [1,3,1,4,1,3,2], queries = [0,3,5]
输出: [2,-1,3]
解释:
查询 0:下标 queries[0] = 0 处的元素为 nums[0] = 1 。最近的相同值下标为 2,距离为 2。
查询 1:下标 queries[1] = 3 处的元素为 nums[3] = 4 。不存在其他包含值 4 的下标,因此结果为 -1。
查询 2:下标 queries[2] = 5 处的元素为 nums[5] = 3 。最近的相同值下标为 1,距离为 3(沿着循环路径:5 -> 6 -> 0 -> 1)。

示例 2:

输入: nums = [1,2,3,4], queries = [0,1,2,3]
输出: [-1,-1,-1,-1]
解释:
数组 nums 中的每个值都是唯一的,因此没有下标与查询的元素值相同。所有查询的结果均为 -1。

说明:

  • 1 <= queries.length <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^6
  • 0 <= queries[i] < nums.length

思路

有一个环形数组 nums 和一个查询数组 queries,返回 元素值与 queries[i] 相同的其它元素之间的最小距离,如果不存在则结果为 -1,返回查询结果数组。

根据元素值分组,分组内记录下标。针对每个查询,二分查找元素在分组中的位置,比较前后下标的距离,如果分组只有一个元素,返回 -1。需要特殊处理首与尾的最近距离。

也可以分组后预处理每个位置的最近距离,统一计算前后的最近距离,查询时直接取结果即可。注意循环数组的距离处理,这里直接将超出的距离映射回了原数组下标,因此最近距离需要取 min(d, n - d),其中 d = abs(i - j) 表示下标 ij 的距离。

代码


/**
 * @date 2026-04-16 8:55
 */
public class SolveQueries3488 {

    public List<Integer> solveQueries_v1(int[] nums, int[] queries) {
        Map<Integer, List<Integer>> map = new HashMap<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            map.putIfAbsent(nums[i], new ArrayList<>());
            map.get(nums[i]).add(i);
        }
        int[] dis = new int[n];
        for (List<Integer> list : map.values()) {
            int size = list.size();
            for (int i = 0; i < size; i++) {
                int index = list.get(i);
                if (size >= 2) {
                    int prev = Math.abs(index - list.get((size + i - 1) % size));
                    int next = Math.abs(list.get((i + 1) % size) - index);
                    dis[index] = Math.min(Math.min(prev, n - prev), Math.min(next, n - next));
                } else {
                    dis[index] = -1;
                }
            }
        }
        List<Integer> res = new ArrayList<>(queries.length);
        for (int query : queries) {
            res.add(dis[query]);
        }
        return res;
    }

}

性能

2515.到目标字符串的最短距离

目标

给你一个下标从 0 开始的 环形 字符串数组 words 和一个字符串 target 。环形数组 意味着数组首尾相连。

  • 形式上, words[i] 的下一个元素是 words[(i + 1) % n] ,而 words[i] 的前一个元素是 words[(i - 1 + n) % n] ,其中 n 是 words 的长度。

从 startIndex 开始,你一次可以用 1 步移动到下一个或者前一个单词。

返回到达目标字符串 target 所需的最短距离。如果 words 中不存在字符串 target ,返回 -1 。

示例 1:

输入:words = ["hello","i","am","leetcode","hello"], target = "hello", startIndex = 1
输出:1
解释:从下标 1 开始,可以经由以下步骤到达 "hello" :
- 向右移动 3 个单位,到达下标 4 。
- 向左移动 2 个单位,到达下标 4 。
- 向右移动 4 个单位,到达下标 0 。
- 向左移动 1 个单位,到达下标 0 。
到达 "hello" 的最短距离是 1 。

示例 2:

输入:words = ["a","b","leetcode"], target = "leetcode", startIndex = 0
输出:1
解释:从下标 0 开始,可以经由以下步骤到达 "leetcode" :
- 向右移动 2 个单位,到达下标 2 。
- 向左移动 1 个单位,到达下标 2 。
到达 "leetcode" 的最短距离是 1 。

示例 3:

输入:words = ["i","eat","leetcode"], target = "ate", startIndex = 0
输出:-1
解释:因为 words 中不存在字符串 "ate" ,所以返回 -1 。

说明:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 100
  • words[i] 和 target 仅由小写英文字母组成
  • 0 <= startIndex < words.length

思路

循环字符串数组 words,从 startIndex 开始,向左或向右查找 target,返回 targetstartIndex 最短的距离,如果不存在返回 -1

从前向后遍历,如果找到 target,记录循环数组中的距离,d 或者 n - d,返回所有距离中的最小值。

或值从 startIndex 开始遍历距离,如果找到 target 则直接返回,需要处理循环数组的下标,(startIndex + i) % n(startIndex - i + n) % n

代码


/**
 * @date 2026-04-15 8:47
 */
public class ClosestTarget2515 {

    public int closestTarget(String[] words, String target, int startIndex) {
        int n = words.length;
        for (int i = 0; i < n; i++) {
            if (words[(startIndex + i) % n].equals(target) || words[(startIndex - i + n) % n].equals(target)) {
                return i;
            }
        }
        return -1;
    }
}

性能