镜像对之间最小绝对距离-LeetCode
3761.镜像对之间最小绝对距离
🎯 问题描述
描述:
给你一个整数数组 nums。
如果两个下标 i 和 j 满足 nums[i] 和 nums[j] 互为镜像数(即一个数是另一个数的数字反转,例如 123 和 321),则称它们构成一个镜像对。
请你返回所有镜像对中,下标距离 |i - j| 的最小值。
如果不存在镜像对,返回 -1。
说明:
-
这是一个哈希表结合贪心策略的问题。
-
镜像定义:
x的镜像是reverse(x)。注意,如果一个数是回文数(如 121),它的镜像是它自己。 -
核心难点:我们需要同时匹配
x和reverse(x)。 -
策略:利用哈希表存储“最近一次出现的位置”。关键在于,我们将原数和镜像数映射到同一个逻辑空间中进行更新。
-
示例:
-
示例 1:
1 | 输入:nums = [12, 21, 3, 3] |
💻 解题思路
思路1:动态哈希更新(同槽竞争法)
核心逻辑
我们需要找到 nums[i] 和之前出现的某个数 nums[j],使得 nums[i] == reverse(nums[j])。
这等价于 reverse(nums[i]) == nums[j]。
代码采用了一种非常紧凑的写法:
- 查找:检查当前数字
num是否已经在哈希表中。- 如果
num在表中,说明之前出现过num或者 出现过num的镜像(因为之前的某个数的镜像计算结果可能正好是num,并存入了表中)。 - 计算距离并更新答案。
- 如果
- 更新:计算当前数字的镜像
m。- 将
m的位置更新为当前下标i:count[m] = i。 - 精妙之处:
- 如果当前是
12,我们存入count[21] = i。这意味着:“如果你在后面遇到了 21,请记得我(12)在这里”。 - 如果当前是
21,我们存入count[12] = i。这意味着:“如果你在后面遇到了 12,请记得我(21)在这里”。 - 如果当前是
121(回文),我们存入count[121] = i。
- 如果当前是
- 将
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 其中 是数组长度, 是数字的最大值。
- 遍历数组 。
- 字符串反转操作
str(num)[::-1]耗时 。 - 哈希表操作平均 。
- 空间复杂度:
- 哈希表存储数字及其下标。
💡 思考
-
“同槽竞争”机制:
- 这是代码最精彩的地方。
- 通常我们会想:
count[num] = i。 - 但这里我们存的是
count[mirror(num)] = i。 - 这意味着哈希表的键不仅是“数字本身”,而是“谁能和我配对”。
- 例如:遇到
12,我们在count[21]处写下i。如果后面真的来了21,它查count[21]就能找到12的位置。
-
回文数的处理:
- 如果
num = 121,则m = 121。 - 代码执行
count[121] = i。 - 如果后面又来了
121,它查count[121]能找到前一个121。 - 逻辑完美自洽。
- 如果
-
为什么不需要存
count[num]?- 若两数分别为 120 和21
- 21的反转12不在哈希表里
-
边界情况:
- 数组长度 1:无法配对,返回 -1。
- 没有镜像对:
ans保持inf,返回 -1。 - 大数:
int(str(num)[::-1])能正确处理。
-
代码细节:
ans <= 10**9:这是一个哨兵判断。因为题目中距离最大也就是 ,如果ans还是初始的大值(或者题目给定的无穷大),说明没找到。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






