题目来源:🔒LeetCode244:最短单词距离 II
问题抽象: 设计一个支持多次查询的数据结构,用于高效计算字符串数组中两个不同单词的最短索引距离,满足以下核心需求:
-
数据结构初始化:
- 接收字符串数组
words
作为构造参数; - 预存储每个单词的所有升序索引(如
{"word": [index1, index2, ...]}
),确保后续查询效率。
- 接收字符串数组
-
查询方法定义:
- 提供
shortest(word1, word2)
方法,返回两单词在数组中任意索引差的最小绝对值; - 需通过双指针合并有序索引列表计算最小距离:
- 遍历两单词的索引列表(均升序),动态比较差值
|list1[i] - list2[j]|
; - 根据索引大小交替移动指针(较小索引的指针右移),维护全局最小值。
- 遍历两单词的索引列表(均升序),动态比较差值
- 提供
-
性能约束:
- 初始化时间复杂度 O(n):遍历数组一次(
n
为数组长度); - 查询时间复杂度 O(L1 + L2):
L1
、L2
为两单词的索引列表长度(双指针线性合并); - 空间复杂度 O(m):
m
为不同单词数量(存储所有单词的索引列表)。
- 初始化时间复杂度 O(n):遍历数组一次(
-
边界保证:
- 输入数组非空,
word1
和word2
不同且均存在(无需校验); - 索引差最小值为
1
(两单词至少相隔一个位置),最大为数组长度减1
。
- 输入数组非空,
初始化输入:字符串数组 words
方法调用输入:字符串 word1
, word2
输出:整数(最短距离,值域 [1, len(words)-1]
)
解题思路
-
核心问题:
由于shortest()
会被频繁调用,需避免每次重新遍历整个列表。高效方案是预处理单词索引,在构造函数中用哈希表记录每个单词的所有出现位置(索引列表),查询时直接操作索引列表。 -
索引列表的特性:
索引列表天然有序(按插入顺序递增),因此可将问题转化为: 求两个有序数组的元素间的最小绝对差。 -
优化查询算法:
- 暴力法(O(MN)):双循环遍历两列表,计算所有组合的差值。
- 双指针法(O(M+N)):
使用指针i
和j
分别遍历两个索引列表。每次计算|list1[i] - list2[j]|
并更新最小值,然后将指向较小值的指针后移(因数组有序,移动较小指针可能缩小差值)。
代码实现(Java版)🔥点击下载源码
class WordDistance {
private Map<String, List<Integer>> wordIndexMap; // 存储单词及其索引列表
public WordDistance(String[] wordsDict) {
wordIndexMap = new HashMap<>();
for (int i = 0; i < wordsDict.length; i++) {
// 若单词未记录则初始化列表,否则追加索引
wordIndexMap.computeIfAbsent(wordsDict[i], k -> new ArrayList<>()).add(i);
}
}
public int shortest(String word1, String word2) {
List<Integer> list1 = wordIndexMap.get(word1); // 获取word1的索引列表
List<Integer> list2 = wordIndexMap.get(word2); // 获取word2的索引列表
int i = 0, j = 0;
int minDist = Integer.MAX_VALUE;
while (i < list1.size() && j < list2.size()) {
int idx1 = list1.get(i);
int idx2 = list2.get(j);
minDist = Math.min(minDist, Math.abs(idx1 - idx2)); // 更新最小距离
// 移动指向较小索引的指针
if (idx1 < idx2) {
i++;
} else {
j++;
}
}
return minDist;
}
}
代码说明
-
构造函数
WordDistance(String[] wordsDict)
:- 时间复杂度 O(N):遍历一次列表,将每个单词及其索引存入
HashMap
。 - 空间复杂度 O(N):最坏情况下所有单词不同,需存储所有索引。
- 时间复杂度 O(N):遍历一次列表,将每个单词及其索引存入
-
查询方法
shortest(String word1, String word2)
:- 时间复杂度 O(M+N):
M
和N
分别为两单词的出现次数。双指针遍历时,每次移动一个指针直至任一列表结束。 - 关键操作:
- 通过
wordIndexMap
直接获取索引列表(O(1)); - 双指针仅遍历最小必要路径(两列表长度之和)。
- 通过
- 时间复杂度 O(M+N):