每日一道leetcode(2026.04.16):距离最小相等元素查询

每日一道leetcode(2026.04.16):距离最小相等元素查询

  • [1. 题目](#1. 题目)
  • [2. 分析](#2. 分析)
  • [3. 代码实现](#3. 代码实现)

1. 题目

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

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

数组 nums 中下标 queriesi 处的元素与 任意 其他下标 j(满足 numsj == numsqueries\[i])之间的 最小 距离。如果不存在这样的下标 j,则该查询的结果为 -1 。 返回一个数组answer,其大小与 queries 相同,其中 answeri 表示查询i的结果。

示例 1:

输入: nums = 1,3,1,4,1,3,2, queries = 0,3,5

输出: 2,-1,3

解释:

查询 0:下标 queries0 = 0 处的元素为 nums0 = 1 。最近的相同值下标为 2,距离为 2。 查询 1:下标queries1 = 3 处的元素为 nums3 = 4 。不存在其他包含值 4 的下标,因此结果为 -1。 查询 2:下标queries2 = 5 处的元素为 nums5 = 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 <= 10e5

1 <= numsi <= 10e6

0 <= queriesi < nums.length

2. 分析

这道题能看到很多其它题型的影子,其实就是快速找到指定下标位置元素值最相近的元素位置。这里我一开始是通过一个数组nums的全遍历,将所有出现的数值放到一个Map中,key为对应的数值,value为出现的所有下标List,这样再确认最小距离的时候,只需要找到指定的下标,然后比较下标前一个和后一个的距离,取较小值即可。

需要稍微注意的是,nums数组表述为环形数组,即下标0和length-1是相连的。

按照这个思路实现逻辑后,通过了绝大多数的测试用例,但倒在了下面这个精心定制的用例上。

在这个用例中,数组nums由特别多是1组成,queries又是分布特别广泛的大数,这样在定位对应的下标时就会执行特别多次循环。

出于这种相同Key值对应List长度超长的情况,我试着使用双向指针的方式去获取最短的距离,所以就基于数组长度以64为间隔,小的范畴仍沿用List中的遍历,大的范畴使用双向指针。

3. 代码实现

java 复制代码
class Solution {
    public List<Integer> solveQueries(int[] nums, int[] queries) {
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (!map.containsKey(nums[i])) {
                map.put(nums[i], new ArrayList<>());
            }
            List<Integer> list = map.get(nums[i]);
            if (list.size() > 64) {
                continue;
            }
            list.add(i);
        }
        int[] res = new int[queries.length];
        for (int i = 0; i < queries.length; i++) {
            int index = queries[i];
            int query = nums[index];
            List<Integer> list = map.get(query);
            if (list == null || list.size() <= 1) {
                res[i] = -1;
                continue;
            }

            if (list.size() > 64) {
                // 使用双向指针进行遍历
                int left = index;
                int right = index;
                int count = 0;
                while (true) {
                    left--;
                    count++;
                    if (left < 0) {
                        left = nums.length - 1;
                    }
                    if (nums[left] == query) {
                        res[i] = count;
                        break;
                    }
                    right++;
                    if (right > nums.length - 1) {
                        right = 0;
                    }
                    if (nums[right] == query) {
                        res[i] = count;
                        break;
                    }
                }
                continue;
            }
            // 使用记录的数组进行遍历
            for (int j = 0; j < list.size(); j++) {
                int val = list.get(j);
                if (val == index) {
                    // 当前查询的位置,比较左边和右边的距离取较小值
                    int left = j == 0 ? val + nums.length - list.get(list.size() - 1) : val - list.get(j - 1);
                    int right = j == list.size() - 1 ? nums.length - val + list.get(0) : list.get(j + 1) - val;
                    res[i] = Math.min(left, right);
                    break;
                }
            }
        }
        return IntStream.of(res).boxed().collect(Collectors.toList());
    }
}
相关推荐
To_OC7 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎8 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC8 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
delishcomcn9 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹9 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术10 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
CV-Climber13 小时前
检索技术的实际应用
人工智能·算法
hhzz13 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_14 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法