|
| 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 | + |
| 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