Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 and word2 and return the shortest distance between these two words in the list. Your method will be called repeatedly many times with different parameters.
Example:
Assume that words = ["practice", "makes", "perfect", "coding", "makes"]
.
Input: word1 =“coding”
, word2 =“practice”
Output: 3
Input: word1 ="makes"
, word2 ="coding"
Output: 1
Note:
You may assume that word1 does not equal to word2, and word1 and word2 are both in the list.
這道題是之前那道 Shortest Word Distance 的拓展,不同的是這次我們需要多次調用求最短單詞距離的函數,那么用之前那道題的解法二和三就非常不高效,而當時摒棄的解法一的思路卻可以用到這里,這里用 HashMap 來建立每個單詞和其所有出現的位置的映射,然后在找最短單詞距離時,只需要取出該單詞在 HashMap 中映射的位置數組進行兩兩比較即可,參見代碼如下:
解法一:
class WordDistance { public: WordDistance(vector<string>& words) { for (int i = 0; i < words.size(); ++i) { m[words[i]].push_back(i); } } int shortest(string word1, string word2) { int res = INT_MAX; for (int i = 0; i < m[word1].size(); ++i) { for (int j = 0; j < m[word2].size(); ++j) { res = min(res, abs(m[word1][i] - m[word2][j])); } } return res; } private: unordered_map<string, vector<int> > m; };
我們可以優化上述的代碼,使查詢的復雜度由上面的 O(MN) 變為 O(M+N),其中M和N為兩個單詞的長度,需要兩個指針i和j來指向位置數組中的某個位置,開始初始化都為0,然后比較位置數組中的數字,將較小的一個的指針向后移動一位,直至其中一個數組遍歷完成即可,參見代碼如下:
解法二:
class WordDistance { public: WordDistance(vector<string>& words) { for (int i = 0; i < words.size(); ++i) { m[words[i]].push_back(i); } } int shortest(string word1, string word2) { int i = 0, j = 0, res = INT_MAX; while (i < m[word1].size() && j < m[word2].size()) { res = min(res, abs(m[word1][i] - m[word2][j])); m[word1][i] < m[word2][j] ? ++i : ++j; } return res; } private: unordered_map<string, vector<int> > m; };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/244
類似題目:
參考資料:
https://leetcode.com/problems/shortest-word-distance-ii/
https://leetcode.com/problems/shortest-word-distance-ii/discuss/67028/Java-Solution-using-HashMap
https://leetcode.com/problems/shortest-word-distance-ii/discuss/67066/9-line-O(n)-C%2B%2B-Solution