Skip to content

Commit d159669

Browse files
committed
Create 821.shortest-distance-to-a-character.md
1 parent 25d0694 commit d159669

File tree

1 file changed

+248
-0
lines changed

1 file changed

+248
-0
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
# 题目地址(821. 字符的最短距离)
2+
3+
https://leetcode-cn.com/problems/shortest-distance-to-a-character
4+
5+
## 题目描述
6+
7+
```
8+
给定一个字符串 S 和一个字符 C。返回一个代表字符串 S 中每个字符到字符串 S 中的字符 C 的最短距离的数组。
9+
10+
示例 1:
11+
12+
输入: S = "loveleetcode", C = 'e'
13+
输出: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]
14+
说明:
15+
16+
- 字符串 S 的长度范围为 [1, 10000]。
17+
- C 是一个单字符,且保证是字符串 S 里的字符。
18+
- S 和 C 中的所有字母均为小写字母。
19+
20+
```
21+
22+
## 前置知识
23+
24+
- 数组的遍历(正向遍历和反向遍历)
25+
26+
## 思路
27+
28+
这道题就是让我们求的是向左或者向右距离目标字符最近的距离。
29+
30+
我画了个图方便大家理解:
31+
32+
![](https://tva1.sinaimg.cn/large/0081Kckwly1gka46lqwlej30rc0f2tae.jpg)
33+
34+
比如我们要找第一个字符 l 的最近的字符 e,直观的想法就是向左向右分别搜索,遇到字符 e 就停止,比较两侧的距离,并取较小的即可。如上图,l 就是 3,c 就是 2。
35+
36+
这种直观的思路用代码来表示的话是这样的:
37+
38+
Python Code:
39+
40+
```py
41+
class Solution:
42+
def shortestToChar(self, S: str, C: str) -> List[int]:
43+
ans = []
44+
45+
for i in range(len(S)):
46+
# 从 i 向左向右扩展
47+
l = r = i
48+
# 向左找到第一个 C
49+
while l > -1:
50+
if S[l] == C: break
51+
l -= 1
52+
# 向左找到第一个 C
53+
while r < len(S):
54+
if S[r] == C: break
55+
r += 1
56+
# 如果至死没有找到,则赋值一个无限大的数字,由于题目的数据范围是 [1, 10000],因此 -10000 或者 10000就够了。
57+
if l == -1: l = -10000
58+
if r == len(S): r = 10000
59+
# 选较近的即可
60+
ans.append(min(r - i, i - l))
61+
return ans
62+
```
63+
64+
**复杂度分析**
65+
66+
- 时间复杂度:$O(N^2)$
67+
- 空间复杂度:$O(1)$
68+
69+
由于题目的数据范围是 $10^4$,因此通过所有的测试用例是没有问题的。
70+
71+
但是实际上,我们可以在线性的时间内解决。这里的关键点和上面的解法类似,也是两端遍历。不过不再是盲目的查找,因为这样做会有很多没有必要的计算。
72+
73+
我们可以使用空间换时间的方式来解,这里我使用类似单调栈的解法来解,大家也可以使用其他手段。关于单调栈的技巧,不在这里展开,感兴趣的可以期待我后面的专题。
74+
75+
```py
76+
class Solution:
77+
def shortestToChar(self, S: str, C: str) -> List[int]:
78+
ans = [10000] * len(S)
79+
stack = []
80+
for i in range(len(S)):
81+
while stack and S[i] == C:
82+
ans[stack.pop()] = i - stack[-1]
83+
if S[i] != C:stack.append(i)
84+
else: ans[i] = 0
85+
for i in range(len(S) - 1, -1, -1):
86+
while stack and S[i] == C:
87+
ans[stack.pop()] = min(ans[stack[-1]], stack[-1] - i)
88+
if S[i] != C:stack.append(i)
89+
else: ans[i] = 0
90+
91+
return ans
92+
```
93+
94+
**复杂度分析**
95+
96+
- 时间复杂度:$O(N)$
97+
- 空间复杂度:$O(N)$
98+
99+
实际上,我们根本不需要栈来存储。原因很简单,那就是每次我们碰到目标字符 C 的时候, 我们就把栈**全部清空**了,因此我们用一个变量标识即可,具体参考后面的代码区。
100+
101+
> 如果碰到目标字符 C 的时候,不把栈清空,那么这个栈的空间多半是不能省的,反之可以省。
102+
103+
## 代码
104+
105+
代码支持:Python3,Java, CPP, Go, PHP
106+
107+
Python3 Code:
108+
109+
```py
110+
class Solution:
111+
def shortestToChar(self, S: str, C: str) -> List[int]:
112+
pre = -10000
113+
ans = []
114+
115+
for i in range(len(S)):
116+
if S[i] == C: pre = i
117+
ans.append(i - pre)
118+
pre = 10000
119+
for i in range(len(S) - 1, -1, -1):
120+
if S[i] == C: pre = i
121+
ans[i] = min(ans[i], pre - i)
122+
return ans
123+
```
124+
125+
Java Code:
126+
127+
```java
128+
class Solution {
129+
public int[] shortestToChar(String S, char C) {
130+
int N = S.length();
131+
int[] ans = new int[N];
132+
int prev = -10000;
133+
134+
for (int i = 0; i < N; ++i) {
135+
if (S.charAt(i) == C) prev = i;
136+
ans[i] = i - prev;
137+
}
138+
139+
prev = 10000;
140+
for (int i = N-1; i >= 0; --i) {
141+
if (S.charAt(i) == C) prev = i;
142+
ans[i] = Math.min(ans[i], prev - i);
143+
}
144+
145+
return ans;
146+
}
147+
}
148+
```
149+
150+
CPP Code:
151+
152+
```cpp
153+
class Solution {
154+
public:
155+
vector<int> shortestToChar(string S, char C) {
156+
vector<int> ans(S.size(), 0);
157+
int prev = -10000;
158+
for(int i = 0; i < S.size(); i ++){
159+
if(S[i] == C) prev = i;
160+
ans[i] = i - prev;
161+
}
162+
prev = 10000;
163+
for(int i = S.size() - 1; i >= 0; i --){
164+
if(S[i] == C) prev = i;
165+
ans[i] = min(ans[i], prev - i);
166+
}
167+
return ans;
168+
}
169+
};
170+
```
171+
172+
Go Code:
173+
174+
```go
175+
func shortestToChar(S string, C byte) []int {
176+
N := len(S)
177+
ans := make([]int, N)
178+
179+
pre := -N // 最大距离
180+
for i := 0; i < N; i++ {
181+
if S[i] == C {
182+
pre = i
183+
}
184+
ans[i] = i - pre
185+
}
186+
187+
pre = N*2 // 最大距离
188+
for i := N - 1; i >= 0; i-- {
189+
if S[i] == C {
190+
pre = i
191+
}
192+
ans[i] = min(ans[i], pre-i)
193+
}
194+
return ans
195+
}
196+
197+
func min(a, b int) int {
198+
if a < b {
199+
return a
200+
}
201+
return b
202+
}
203+
```
204+
205+
PHP Code:
206+
207+
```php
208+
class Solution
209+
{
210+
211+
/**
212+
* @param String $S
213+
* @param String $C
214+
* @return Integer[]
215+
*/
216+
function shortestToChar($S, $C)
217+
{
218+
$N = strlen($S);
219+
$ans = [];
220+
221+
$pre = -$N;
222+
for ($i = 0; $i < $N; $i++) {
223+
if ($S[$i] == $C) {
224+
$pre = $i;
225+
}
226+
$ans[$i] = $i - $pre;
227+
}
228+
229+
$pre = $N * 2;
230+
for ($i = $N - 1; $i >= 0; $i--) {
231+
if ($S[$i] == $C) {
232+
$pre = $i;
233+
}
234+
$ans[$i] = min($ans[$i], $pre - $i);
235+
}
236+
return $ans;
237+
}
238+
}
239+
```
240+
241+
**复杂度分析**
242+
243+
- 时间复杂度:$O(N)$
244+
- 空间复杂度:$O(1)$
245+
246+
大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
247+
248+
大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。

0 commit comments

Comments
 (0)