不能直接用 std::min_element 找最短距离,因为它找值最小元素而非值相等元素的最小下标差;题目要求在值相等前提下找下标差绝对值最小的两个元素,暴力法需双重循环并剪枝优化。

为什么不能直接用 std::min_element 找最短距离?
因为 std::min_element 找的是值最小的元素,不是位置最近的两个元素。题目要的是“数组中任意两个元素下标差的绝对值最小”,但前提是这两个元素的**值相等**(否则“距离”无意义——你总不能说 1 和 100 距离近吧?)。实际业务中,这个需求通常出现在:去重前找重复项位置、检测相邻相同状态、压缩序列时识别紧邻重复等场景。
常见错误是误读题意,写成找值最接近的两个数(那是另一类问题,需排序后双指针),或者忽略“相等”前提,直接算所有两两下标差——时间复杂度飙到 O(n²),大数组直接卡死。
暴力法适用小数组,但要注意边界和提前退出
如果数组长度 n ≤ 1000,双重循环仍可接受。关键不是写出来,而是写对:
- 外层索引
i从0到n-2,内层j从i+1开始,避免自比和重复计算 - 只在
arr[i] == arr[j]时更新最小距离min_dist = std::min(min_dist, j - i)(因为j > i,不用abs) - 一旦
min_dist == 1,可立即break——不可能比相邻更近了
示例片段:
立即学习“C++免费学习笔记(深入)”;
int min_dist = INT_MAX;
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
if (arr[i] == arr[j]) {
min_dist = std::min(min_dist, j - i);
if (min_dist == 1) break;
}
}
if (min_dist == 1) break;
}哈希表一次遍历解决,适合大数组
核心思路:对每个值记录它**上一次出现的位置**。遇到重复值时,用当前索引减去上次索引,就是这对元素的距离。时间复杂度 O(n),空间 O(n)。
注意点:
- 用
std::unordered_map<T, int>存值 → 上次下标,初始化为空 - 遍历时,若该值已在 map 中,计算
current_index - last_index并更新最小距离 - 每次都要更新 map 中该值对应的下标为当前索引(保证下次算的是最新一次的距离)
- 整型数组若含负数或大数,
unordered_map没问题;但若元素类型是自定义类,需提供hash和==
示例关键逻辑:
std::unordered_map<int, int> last_seen;
int min_dist = INT_MAX;
for (int i = 0; i < n; ++i) {
if (last_seen.find(arr[i]) != last_seen.end()) {
min_dist = std::min(min_dist, i - last_seen[arr[i]]);
}
last_seen[arr[i]] = i;
}当数组已排序时,别浪费性质——用单次扫描
如果输入保证升序(或降序),重复元素必然连续出现。此时不需要哈希表,也不用二重循环:一遍扫描,只比较 arr[i] 和 arr[i-1] 即可。
要点:
- 从
i = 1开始,检查arr[i] == arr[i-1] - 成立则距离为
1,直接可设min_dist = 1并继续(因为可能有更短?不,1 就是最短) - 但注意:如果只要求返回最小距离值,扫到第一个重复就能返回 1;如果要求返回具体哪两个下标,则需记下
i-1和i - 若数组未排序却强行用此法,结果完全错误——这点极易被忽略
排序前提下的最简实现:
int min_dist = INT_MAX;
for (int i = 1; i < n; ++i) {
if (arr[i] == arr[i-1]) {
min_dist = 1;
break;
}
}真正容易被忽略的是“相等”这个隐含前提——很多人在调试时发现结果不对,最后才发现自己一直在算不同值之间的下标差。另外,INT_MAX 初始化后没找到重复时需要单独处理,否则返回一个极大值会掩盖逻辑错误。


















