# 【Day 30】面试题 17.11. 单词距离

# 题目描述

有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离(相隔单词数)。如果寻找过程在这个文件中会重复多次,而每次寻找的单词不同,你能对此优化吗?

示例:

输入:words = ["I","am","a","student","from","a","university","in","a","city"], word1 = "a", word2 = "student" 输出:1 提示:

words.length <= 100000

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/find-closest-lcci 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

# 我的回答

# 解法一

# 时间复杂度 O(n^2) 最复杂的情况(n/2)^2?

# 空间复杂度 O(n) 最长应该也就一个 n 的空间

var findClosest = function (words, word1, word2) {
    let wordArr = []
    let word2Arr = []
    for (let i = 0; i < words.length; i++) {
        if (words[i] === word1) wordArr.push(i)
        if (words[i] === word2) word2Arr.push(i)
    }
    let short = Infinity
    for (let i of wordArr) {
        for (let j of word2Arr) {
            short = Math.min(short, Math.abs(i - j))
        }
    }
    return short
};

# 解法二

# 时间复杂度 O(n) 一个循环

# 空间复杂度 O(1) 三个参数空间

奇怪了,怎么还没第一个跑得快

var findClosest = function (words, word1, word2) {
    let word1Pos = 0
    let word2Pos = 0
    let short = Infinity
    for (let i = 0; i < words.length; i++) {
        if (words[i] === word1) word1Pos = i
        if (words[i] === word2) word2Pos = i
        if (word1Pos && word2Pos) short = Math.min(short, Math.abs(word1Pos - word2Pos))
        if (short <= 1) break
    }
    return short
};

# 参考回答

# 前置知识

  • 哈希
  • 空间换时间
  • 双指针

# 两个数组

# 思路

一个简单的思路是:分别找出 word1 和 word2 在 words 中的所有出现的索引 ids1 和 ids2。于是问题转换为:从两个有序数组分别选一个数,使得二者差的绝对值最小。

# 代码

代码支持: Python

Python Code:

class Solution:
    def findClosest(self, words: List[str], word1: str, word2: str) -> int:
        # [2,5,8]
        ids1 = []
        # [3]
        ids2 = []
        ans = len(words)

        for i in range(len(words)):
            if words[i] == word1:
                ids1.append(i)
            if words[i] == word2:
                ids2.append(i)
        i = j = 0
        while i < len(ids1) and j < len(ids2):
            if ids1[i] < ids2[j]:
                ans = min(ans, ids2[j] - ids1[i])
                i += 1
            else:
                ans = min(ans, ids1[i] - ids2[j])
                j += 1

        return ans

复杂度分析

  • 时间复杂度:$O(N)$,其中 N 为 words 的长度。
  • 空间复杂度:$O(N)$,其中 N 为 words 的长度。

# 双指针

# 思路

实际上,上面的数组是没有必要的。我们可以边遍历边计算,从而在 One Pass 内完成,并且只占用常数空间。

# 代码

代码支持: Python, C++

Python Code:

class Solution:
    def findClosest(self, words: List[str], word1: str, word2: str) -> int:
        ans = len(words)
        id1 = id2 = -1
        for i in range(len(words)):
            if words[i] == word1:
                id1 = i
            if words[i] == word2:
                id2 = i
            if id1 != -1 and id2 != -1:
                ans = min(ans, abs(id1 - id2))
        return ans

C++ Code:

class Solution {
    public:
    int findClosest(vector < string > & words, string word1, string word2) {

        int id1 = -1, id2 = -1, ans = words.size()
        for (int i=0
             i < words.size()
             i + +) {
            if (words[i] == word1) id1 = i
            if (words[i] == word2) id2 = i
            if (id1 != -1 && id2 != -1) ans = min(ans, abs(id1 - id2))
        }
        return ans
    }
}

复杂度分析

  • 时间复杂度:$O(N)$,其中 N 为 words 的长度。
  • 空间复杂度:$O(1)$
Last Updated: 12/22/2022, 9:53:26 AM