2026-03-28:三个相等元素之间的最小距离Ⅰ。用go语言,给定一个整数数组 nums。
如果存在三个互不相同的位置 i、j、k,并且满足 nums[i] = nums[j] = nums[k],那么这三个下标组成的三元组 (i, j, k) 称为有效三元组。
对于任意一个有效三元组,它的距离定义为:
|i - j| + |j - k| + |k - i|
其中 |x| 表示 x 的绝对值。
你需要在所有有效三元组中找出距离的最小值并返回。
如果数组中根本找不到有效三元组,则返回 -1。
1 <= n == nums.length <= 100。
1 <= nums[i] <= n。
输入: nums = [1,2,1,1,3]。
输出: 6。
解释:
最小距离对应的有效三元组是 (0, 2, 3) 。
(0, 2, 3) 是一个有效三元组,因为 nums[0] == nums[2] == nums[3] == 1。它的距离为 abs(0 - 2) + abs(2 - 3) + abs(3 - 0) = 2 + 1 + 3 = 6。
题目来自力扣3740。
分步骤详细解题过程
步骤1:遍历数组,提前判断「最快满足最小距离」的情况
从头开始逐个遍历数组元素,同时做一个快速判断:
如果发现连续三个元素完全相同(比如 [1,1,1]),
那么这三个下标就是连续的,计算出的距离一定是最小的固定值 4,
直接终止所有流程,返回 4 即可。
原因:连续三个相同元素的下标差最小,计算出的距离是所有可能里最小的,无需再计算其他情况。
步骤2:记录每个数字出现的所有下标
创建一个「映射表」:
- 键:数组中的数字
- 值:该数字所有出现位置的下标列表(按从小到大顺序存储)
举例:输入 [1,2,1,1,3]
映射表结果:
- 1 → [0, 2, 3]
- 2 → [1]
- 3 → [4]
只有下标列表长度 ≥3 的数字,才可能形成有效三元组。
步骤3:遍历所有可能形成有效三元组的数字
只处理映射表中「下标数量 ≥3」的数字,其他数字直接跳过。
步骤4:对每个数字的下标列表,计算最小三元组距离
因为下标是从小到大有序的,有效三元组一定是连续的三个下标(非连续的下标差更大,距离也更大):
- 取第 0、1、2 个下标
- 取第 1、2、3 个下标
- 取第 2、3、4 个下标…… 以此类推。
对每一组连续三个下标,用简化公式计算: 距离 = 2 × (最大下标 - 最小下标) 并记录所有计算结果中的最小值。
举例:数字 1 的下标 [0,2,3] 唯一一组连续三个下标:0、2、3 距离 = 2 × (3 - 0) = 6
步骤5:最终结果判断
- 如果找到有效三元组:返回记录的最小距离
- 如果没有任何有效三元组:返回 -1
本题完整执行演示(输入 [1,2,1,1,3])
- 遍历数组,没有连续三个相同元素,快速判断不触发
- 记录下标:1→[0,2,3],2→[1],3→[4]
- 只有数字 1 有 ≥3 个下标
- 计算唯一三元组 [0,2,3]:距离=2×(3-0)=6
- 最小距离为 6,返回 6
时间复杂度 & 额外空间复杂度
1. 总时间复杂度
O(n)
- 遍历数组记录下标:执行 n 次操作
- 遍历映射表计算距离:所有数字的下标总数加起来就是 n,总操作不超过 n
- 整体操作次数与数组长度 n 成正比
2. 总额外空间复杂度
O(n)
- 用到的映射表,最坏情况下(数组所有数字都不同),存储 n 个键值对
- 占用的额外空间与数组长度 n 成正比
总结
- 解题核心:先快速判断连续三元素,再记录数字下标,用有序连续下标计算最小距离;
- 时间复杂度:O(n)(线性时间);
- 额外空间复杂度:O(n)(线性空间)。
Go完整代码如下:
package main
import (
"fmt"
"math"
)
func minimumDistance(nums []int) int {
pos := map[int][]int{}
for i, x := range nums {
if i >= 2 && x == nums[i-1] && x == nums[i-2] {
return 4
}
pos[x] = append(pos[x], i)
}
ans := math.MaxInt
for _, p := range pos {
for i := 2; i < len(p); i++ {
ans = min(ans, (p[i]-p[i-2])*2)
}
}
if ans == math.MaxInt {
return -1
}
return ans
}
func main() {
nums := []int{1, 2, 1, 1, 3}
result := minimumDistance(nums)
fmt.Println(result)
}
Python完整代码如下:
# -*-coding:utf-8-*-
from typing import List
def minimumDistance(nums: List[int]) -> int:
pos = {}
for i, x in enumerate(nums):
# 检查是否有三个连续相同的元素
if i >= 2 and x == nums[i-1] and x == nums[i-2]:
return 4
if x not in pos:
pos[x] = []
pos[x].append(i)
ans = float('inf')
for p in pos.values():
for i in range(2, len(p)):
ans = min(ans, (p[i] - p[i-2]) * 2)
if ans == float('inf'):
return -1
return ans
if __name__ == "__main__":
nums = [1, 2, 1, 1, 3]
result = minimumDistance(nums)
print(result)
C++完整代码如下:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <climits>
using namespace std;
int minimumDistance(vector<int>& nums) {
unordered_map<int, vector<int>> pos;
for (int i = 0; i < nums.size(); i++) {
int x = nums[i];
// 检查连续三个相同元素
if (i >= 2 && x == nums[i-1] && x == nums[i-2]) {
return 4;
}
pos[x].push_back(i);
}
int ans = INT_MAX;
for (auto& entry : pos) {
vector<int>& p = entry.second;
for (int i = 2; i < p.size(); i++) {
ans = min(ans, (p[i] - p[i-2]) * 2);
}
}
if (ans == INT_MAX) {
return -1;
}
return ans;
}
int main() {
vector<int> nums = {1, 2, 1, 1, 3};
int result = minimumDistance(nums);
cout << result << endl;
return 0;
}