Skip to content

Commit 39f3686

Browse files
authored
feat: add solutions to lcci problem: No.17.11 (doocs#2718)
1 parent baf6324 commit 39f3686

File tree

14 files changed

+256
-187
lines changed

14 files changed

+256
-187
lines changed

lcci/17.11.Find Closest/README.md

+92-62
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,27 @@
2020

2121
## 解法
2222

23-
### 方法一
23+
### 方法一:一次遍历
24+
25+
我们用两个指针 $i$ 和 $j$ 分别记录两个单词 $\textit{word1}$ 和 $\textit{word2}$ 最近出现的位置,初始时 $i = \infty$, $j = -\infty$。
26+
27+
接下来我们遍历整个文本文件,对于每个单词 $w$,如果 $w$ 等于 $\textit{word1}$,我们更新 $i = k$,其中 $k$ 是当前单词的下标;如果 $w$ 等于 $\textit{word2}$,我们更新 $j = k$。然后我们更新答案 $ans = \min(ans, |i - j|)$。
28+
29+
遍历结束后,我们返回答案 $ans$。
30+
31+
时间复杂度 $O(n)$,其中 $n$ 是文本文件中的单词数。空间复杂度 $O(1)$。
2432

2533
<!-- tabs:start -->
2634

2735
```python
2836
class Solution:
2937
def findClosest(self, words: List[str], word1: str, word2: str) -> int:
30-
i, j, ans = 1e5, -1e5, 1e5
31-
for k, word in enumerate(words):
32-
if word == word1:
38+
i, j = inf, -inf
39+
ans = inf
40+
for k, w in enumerate(words):
41+
if w == word1:
3342
i = k
34-
elif word == word2:
43+
elif w == word2:
3544
j = k
3645
ans = min(ans, abs(i - j))
3746
return ans
@@ -40,12 +49,12 @@ class Solution:
4049
```java
4150
class Solution {
4251
public int findClosest(String[] words, String word1, String word2) {
43-
int i = 100000, j = -100000, ans = 100000;
52+
final int inf = 1 << 29;
53+
int i = inf, j = -inf, ans = inf;
4454
for (int k = 0; k < words.length; ++k) {
45-
String word = words[k];
46-
if (word.equals(word1)) {
55+
if (words[k].equals(word1)) {
4756
i = k;
48-
} else if (word.equals(word2)) {
57+
} else if (words[k].equals(word2)) {
4958
j = k;
5059
}
5160
ans = Math.min(ans, Math.abs(i - j));
@@ -59,13 +68,15 @@ class Solution {
5968
class Solution {
6069
public:
6170
int findClosest(vector<string>& words, string word1, string word2) {
62-
int i = 1e5, j = -1e5, ans = 1e5;
71+
const int inf = 1 << 29;
72+
int i = inf, j = -inf;
73+
int ans = inf;
6374
for (int k = 0; k < words.size(); ++k) {
64-
string word = words[k];
65-
if (word == word1)
75+
if (words[k] == word1) {
6676
i = k;
67-
else if (word == word2)
77+
} else if (words[k] == word2) {
6878
j = k;
79+
}
6980
ans = min(ans, abs(i - j));
7081
}
7182
return ans;
@@ -75,70 +86,70 @@ public:
7586
7687
```go
7788
func findClosest(words []string, word1 string, word2 string) int {
78-
i, j, ans := 100000, -100000, 100000
79-
for k, word := range words {
80-
if word == word1 {
89+
const inf int = 1 << 29
90+
i, j, ans := inf, -inf, inf
91+
for k, w := range words {
92+
if w == word1 {
8193
i = k
82-
} else if word == word2 {
94+
} else if w == word2 {
8395
j = k
8496
}
85-
ans = min(ans, abs(i-j))
97+
ans = min(ans, max(i-j, j-i))
8698
}
8799
return ans
88100
}
89-
90-
func abs(x int) int {
91-
if x < 0 {
92-
return -x
93-
}
94-
return x
95-
}
96101
```
97102

98103
```ts
99104
function findClosest(words: string[], word1: string, word2: string): number {
100-
let index1 = 100000;
101-
let index2 = -100000;
102-
let res = 100000;
103-
const n = words.length;
104-
for (let i = 0; i < n; i++) {
105-
const word = words[i];
106-
if (word === word1) {
107-
index1 = i;
108-
} else if (word === word2) {
109-
index2 = i;
105+
let [i, j, ans] = [Infinity, -Infinity, Infinity];
106+
for (let k = 0; k < words.length; ++k) {
107+
if (words[k] === word1) {
108+
i = k;
109+
} else if (words[k] === word2) {
110+
j = k;
110111
}
111-
res = Math.min(res, Math.abs(index1 - index2));
112+
ans = Math.min(ans, Math.abs(i - j));
112113
}
113-
return res;
114+
return ans;
114115
}
115116
```
116117

117118
```rust
118119
impl Solution {
119120
pub fn find_closest(words: Vec<String>, word1: String, word2: String) -> i32 {
120-
let mut res = i32::MAX;
121-
let mut index1 = -1;
122-
let mut index2 = -1;
123-
for (i, word) in words.iter().enumerate() {
124-
let i = i as i32;
125-
if word.eq(&word1) {
126-
index1 = i;
127-
} else if word.eq(&word2) {
128-
index2 = i;
121+
let mut ans = i32::MAX;
122+
let mut i = -1;
123+
let mut j = -1;
124+
for (k, w) in words.iter().enumerate() {
125+
let k = k as i32;
126+
if w.eq(&word1) {
127+
i = k;
128+
} else if w.eq(&word2) {
129+
j = k;
129130
}
130-
if index1 != -1 && index2 != -1 {
131-
res = res.min((index1 - index2).abs());
131+
if i != -1 && j != -1 {
132+
ans = ans.min((i - j).abs());
132133
}
133134
}
134-
res
135+
ans
135136
}
136137
}
137138
```
138139

139140
<!-- tabs:end -->
140141

141-
### 方法二
142+
### 方法二:哈希表 + 双指针
143+
144+
我们可以用哈希表 $d$ 记录每个单词出现的位置,然后对于每一对 $\textit{word1}$ 和 $\textit{word2}$,我们可以通过双指针的方法找到它们的最短距离。
145+
146+
我们遍历整个文本文件,对于每个单词 $w$,我们将 $w$ 的下标加入到 $d[w]$ 中。
147+
148+
接下来我们找到 $\textit{word1}$ 和 $\textit{word2}$ 在文本文件中出现的位置,分别用 $idx1$ 和 $idx2$ 表示。然后我们用两个指针 $i$ 和 $j$ 分别指向 $idx1$ 和 $idx2$,初始时 $i = 0$, $j = 0$。
149+
150+
接下来我们遍历 $idx1$ 和 $idx2$,每次我们更新答案 $ans = \min(ans, |idx1[i] - idx2[j]|)$,然后我们将 $i$ 和 $j$ 中较小的那个指针向后移动一位。
151+
152+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是文本文件中的单词数。
142153

143154
<!-- tabs:start -->
144155

@@ -148,7 +159,7 @@ class Solution:
148159
d = defaultdict(list)
149160
for i, w in enumerate(words):
150161
d[w].append(i)
151-
ans = 1e5
162+
ans = inf
152163
idx1, idx2 = d[word1], d[word2]
153164
i, j, m, n = 0, 0, len(idx1), len(idx2)
154165
while i < m and j < n:
@@ -169,7 +180,7 @@ class Solution {
169180
}
170181
List<Integer> idx1 = d.get(word1), idx2 = d.get(word2);
171182
int i = 0, j = 0, m = idx1.size(), n = idx2.size();
172-
int ans = 100000;
183+
int ans = 1 << 29;
173184
while (i < m && j < n) {
174185
int t = Math.abs(idx1.get(i) - idx2.get(j));
175186
ans = Math.min(ans, t);
@@ -189,17 +200,20 @@ class Solution {
189200
public:
190201
int findClosest(vector<string>& words, string word1, string word2) {
191202
unordered_map<string, vector<int>> d;
192-
for (int i = 0; i < words.size(); ++i) d[words[i]].push_back(i);
203+
for (int i = 0; i < words.size(); ++i) {
204+
d[words[i]].push_back(i);
205+
}
193206
vector<int> idx1 = d[word1], idx2 = d[word2];
194207
int i = 0, j = 0, m = idx1.size(), n = idx2.size();
195208
int ans = 1e5;
196209
while (i < m && j < n) {
197210
int t = abs(idx1[i] - idx2[j]);
198211
ans = min(ans, t);
199-
if (idx1[i] < idx2[j])
212+
if (idx1[i] < idx2[j]) {
200213
++i;
201-
else
214+
} else {
202215
++j;
216+
}
203217
}
204218
return ans;
205219
}
@@ -214,9 +228,9 @@ func findClosest(words []string, word1 string, word2 string) int {
214228
}
215229
idx1, idx2 := d[word1], d[word2]
216230
i, j, m, n := 0, 0, len(idx1), len(idx2)
217-
ans := 100000
231+
ans := 1 << 30
218232
for i < m && j < n {
219-
t := abs(idx1[i] - idx2[j])
233+
t := max(idx1[i]-idx2[j], idx2[j]-idx1[i])
220234
if t < ans {
221235
ans = t
222236
}
@@ -228,12 +242,28 @@ func findClosest(words []string, word1 string, word2 string) int {
228242
}
229243
return ans
230244
}
245+
```
231246

232-
func abs(x int) int {
233-
if x < 0 {
234-
return -x
235-
}
236-
return x
247+
```ts
248+
function findClosest(words: string[], word1: string, word2: string): number {
249+
const d: Map<string, number[]> = new Map();
250+
for (let i = 0; i < words.length; ++i) {
251+
if (!d.has(words[i])) {
252+
d.set(words[i], []);
253+
}
254+
d.get(words[i])!.push(i);
255+
}
256+
let [i, j] = [0, 0];
257+
let ans = Infinity;
258+
while (i < d.get(word1)!.length && j < d.get(word2)!.length) {
259+
ans = Math.min(ans, Math.abs(d.get(word1)![i] - d.get(word2)![j]));
260+
if (d.get(word1)![i] < d.get(word2)![j]) {
261+
++i;
262+
} else {
263+
++j;
264+
}
265+
}
266+
return ans;
237267
}
238268
```
239269

0 commit comments

Comments
 (0)