2026-03-28:三个相等元素之间的最小距离Ⅰ。用go语言,给定一个整数数组 nums。 如果存在三个互不相同的位置 i、j、k,并且满足 nums[i]

0 阅读4分钟

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. 如果找到有效三元组:返回记录的最小距离
  2. 如果没有任何有效三元组:返回 -1

本题完整执行演示(输入 [1,2,1,1,3])

  1. 遍历数组,没有连续三个相同元素,快速判断不触发
  2. 记录下标:1→[0,2,3],2→[1],3→[4]
  3. 只有数字 1 有 ≥3 个下标
  4. 计算唯一三元组 [0,2,3]:距离=2×(3-0)=6
  5. 最小距离为 6,返回 6

时间复杂度 & 额外空间复杂度

1. 总时间复杂度

O(n)

  • 遍历数组记录下标:执行 n 次操作
  • 遍历映射表计算距离:所有数字的下标总数加起来就是 n,总操作不超过 n
  • 整体操作次数与数组长度 n 成正比

2. 总额外空间复杂度

O(n)

  • 用到的映射表,最坏情况下(数组所有数字都不同),存储 n 个键值对
  • 占用的额外空间与数组长度 n 成正比

总结

  1. 解题核心:先快速判断连续三元素,再记录数字下标,用有序连续下标计算最小距离;
  2. 时间复杂度:O(n)(线性时间);
  3. 额外空间复杂度: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;
}

在这里插入图片描述