821.字符的最短距离

https://leetcode-cn.com/problems/shortest-distance-to-a-character/

题目描述

解法 1:中心扩展法

思路

这是最符合直觉的思路,对每个字符分别进行如下处理:

  • 从当前下标出发,分别向左、右两个方向去寻找目标字符 C

  • 只在一个方向找到的话,直接计算字符距离。

  • 两个方向都找到的话,取两个距离的最小值。

复杂度分析

  • 时间复杂度:$O(N^2)$,N 为 S 的长度,两层循环。

  • 空间复杂度:$O(1)$。

代码 (JS/C++)

JavaScript Code

C++ Code

解法 2:空间换时间

思路

空间换时间是编程中很常见的一种 trade-off (反过来,时间换空间也是)。

因为目标字符 CS 中的位置是不变的,所以我们可以提前将 C 的所有下标记录在一个数组 cIndices 中。

然后遍历字符串 S 中的每个字符,到 cIndices 中找到距离当前位置最近的下标,计算距离。

复杂度分析

  • 时间复杂度:$O(N*K)$,N 是 S 的长度,K 是字符 C 在字符串中出现的次数,$K <= N$。

  • 空间复杂度:$O(K)$,K 为字符 C 出现的次数,这是记录字符 C 出现下标的辅助数组消耗的空间。

代码 (JS/C++)

JavaScript Code

C++ Code

解法 3:贪心

思路

其实对于每个字符来说,它只关心离它最近的那个 C 字符,其他的它都不管。所以这里还可以用贪心的思路:

  1. 从左往右 遍历字符串 S,用一个数组 left 记录每个字符 左侧 出现的最后一个 C 字符的下标;

  2. 从右往左 遍历字符串 S,用一个数组 right 记录每个字符 右侧 出现的最后一个 C 字符的下标;

  3. 然后同时遍历这两个数组,计算距离最小值。

优化 1

再多想一步,其实第二个数组并不需要。因为对于左右两侧的 C 字符,我们也只关心其中距离更近的那一个,所以第二次遍历的时候可以看情况覆盖掉第一个数组的值:

  1. 字符左侧没有出现过 C 字符

  2. i - left > right - i (i 为当前字符下标,left 为字符左侧最近的 C 下标,right 为字符右侧最近的 C 下标)

如果出现以上两种情况,就可以进行覆盖,最后再遍历一次数组计算距离。

优化 2

如果我们是直接记录 C 与当前字符的距离,而不是记录 C 的下标,还可以省掉最后一次遍历计算距离的过程。

复杂度分析

  • 时间复杂度:$O(N)$,N 是 S 的长度。

  • 空间复杂度:$O(1)$。

代码 (JS/C++/Python)

JavaScript Code

直接计算距离:

JavaScript Code

C++ Code

Python Code

解法 4:窗口

思路

C 看成分界线,将 S 划分成一个个窗口。然后对每个窗口进行遍历,分别计算每个字符到窗口边界的距离最小值。

复杂度分析

  • 时间复杂度:$O(N)$,N 是 S 的长度。

  • 空间复杂度:$O(1)$。

代码 (JS/C++/Python)

JavaScript Code

C++ Code

Python Code

更多题解可以访问:https://github.com/suukii/91-days-algorithm

Last updated

Was this helpful?