数组内单词可能有重复,所以需要在 word1 & word2 的多次出现位置中,寻找最近的。
用一些数组的小 trick,比如 index = -1 作为 “还没找到” 的初始化条件,而两个指针所保存的,都是 word1 / word2 所最近出现的位置,one-pass 即可。
public class Solution {
public int shortestDistance(String[] words, String word1, String word2) {
int minDis = Integer.MAX_VALUE;
int oneIndex = -1, twoIndex = -1;
for(int i = 0; i < words.length; i++){
if(words[i].equals(word1)) oneIndex = i;
if(words[i].equals(word2)) twoIndex = i;
if(oneIndex != -1 && twoIndex != -1)
minDis = Math.min(minDis, Math.abs(oneIndex - twoIndex));
}
return minDis;
}
}
这样的问题设计方式实在提醒自己问清楚问题要求,比如 wordList 大小,是否有重复,函数调用次数是否频繁等等。这题在原先基础上增加了 data structure API 调用的考量。
思路很简单,调用多次之后每次再去重新扫很不经济,需要数据结构去存储每个 word 出现的位置,每次 API 调用时直接在两个 list 中找最小距离。
比较两个 list 的方法类似窗口型双指针的基本思想:虽然双指针所能组成的 pair 数量是 n^2,但是对于指定位置的 ptr,我们可以证明后面的所有 pair 组合都是没有意义的,因此可以把指针单向移动。
public class WordDistance {
HashMap<String, List<Integer>> map;
public WordDistance(String[] words) {
map = new HashMap<String, List<Integer>>();
for(int i = 0; i < words.length; i++){
String str = words[i];
if(map.containsKey(str)){
map.get(str).add(i);
} else {
List<Integer> list = new ArrayList<Integer>();
list.add(i);
map.put(str, list);
}
}
}
public int shortest(String word1, String word2) {
List<Integer> oneList = map.get(word1);
List<Integer> twoList = map.get(word2);
int ptr1 = 0, ptr2 = 0;
int minDis = Integer.MAX_VALUE;
while(ptr1 < oneList.size() && ptr2 < twoList.size()){
minDis = Math.min(minDis, Math.abs(oneList.get(ptr1) - twoList.get(ptr2)));
if(oneList.get(ptr1) < twoList.get(ptr2)){
ptr1 ++;
} else {
ptr2 ++;
}
}
return minDis;
}
}
改成 word1 有可能等于 word2 之后,这题的重点就变成了各种 corner case 怎么处理,比如
【"a","c","a","a"】, word1 = "a", word2 = "a"
【"a", "a"】, word1 = "a", word2 = "a"
换句话讲,就是看你能否考虑到各种情况正确地 assign index.
public class Solution {
public int shortestWordDistance(String[] words, String word1, String word2) {
int ptr1 = -1, ptr2 = -1;
boolean isSame = word1.equals(word2);
int minDis = Integer.MAX_VALUE;
for(int i = 0; i < words.length; i++){
if(words[i].equals(word1)){
if(isSame){
ptr1 = ptr2;
ptr2 = i;
} else {
ptr1 = i;
}
} else if(words[i].equals(word2)){
ptr2 = i;
}
if(ptr1 != -1 && ptr2 != -1) minDis = Math.min(minDis, Math.abs(ptr1 - ptr2));
}
return minDis;
}
}