尽可能使字符串相等-LeetCode
1208. 尽可能使字符串相等
🎯 问题描述(来源于LeetCode)
描述:
给你两个长度相同的字符串 s 和 t。
将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(即两个字符 ASCII 码值的差的绝对值)。
用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算。
如果可以将 s 的某个子字符串转化为 t 中对应的子字符串,请返回可以转化的最大长度。
如果不存在可以转化的子字符串,返回 0。
说明:
-
这是一个不定长滑动窗口问题。
-
核心逻辑是维护一个窗口,使得窗口内所有字符的转换开销之和(总开销)不超过
maxCost。 -
当总开销超过预算时,收缩左边界。
-
示例:
-
示例 1:
1 | 输入:s = "abcd", t = "bcdf", maxCost = 3 |
输入:s = “abcd”, t = “cdef”, maxCost = 3
输出:1
解释:
s 中的 “a” 转化为 “c” 开销为 2。
s 中的 “b” 转化为 “d” 开销为 2。
s 中的 “c” 转化为 “e” 开销为 2。
s 中的 “d” 转化为 “f” 开销为 2。
任意单个字符的开销都 <= 3,所以最大长度为 1。
1 | ## 💻 解题思路 |
class Solution:
def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
count = 0 # 记录满足条件的最长子字符串长度
fare = 0 # 记录当前窗口内的总开销
left = 0 # 窗口左边界
# 右边界 right 随循环遍历字符串
for right in range(len(s)):
# 1. 扩展窗口:计算当前字符的转换开销并加入总开销
f = abs(ord(s[right]) - ord(t[right]))
fare += f
# 2. 收缩窗口:如果总开销超过预算
# 则不断移动左边界,直到总开销恢复为 <= maxCost
while fare > maxCost:
f = abs(ord(s[left]) - ord(t[left]))
fare -= f
left += 1
# 3. 更新答案:此时窗口 [left, right] 内总开销 <= maxCost
count = max(count, right - left + 1)
return count
#### 思路1:📊 性能分析
- **时间复杂度**:O(N)
- 其中N是字符串 `s` 的长度。
- 虽然代码中有一个 `while` 循环嵌套在 `for` 循环中,但每个字符最多被访问两次(一次被右边界 `right` 加入,一次被左边界 `left` 移出)。因此,整体操作次数是线性的。
- **空间复杂度**:O(1)
- 只使用了常数个额外变量 (`count`, `fare`, `left`, `right`, `f`),没有使用额外的数据结构。
#### 思考
1. **不定长窗口**:
- 右边界 `right` 始终向右移动。
- 左边界 `left` 只有在总开销 `fare` 超过 `maxCost` 时才会向右移动。
2. **开销计算**:
- 每个字符的转换开销是 `abs(ord(s[i]) - ord(t[i]))`。
- 使用 `ord()` 函数获取字符的 ASCII 码值。
3. **收缩逻辑**:
- `while fare > maxCost:` 是核心。它保证了在任何时刻,窗口内的总开销都不超过预算。
- 当总开销超支时,我们不断移除左边的字符的开销,直到总开销恢复合法。
4. **答案更新时机**:
- `count = max(count, right - left + 1)` 放在 `while` 循环之后。
- 这保证了我们只在窗口满足“总开销 <= maxCost”这一合法条件时,才去更新最大长度。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






