1. 题目
给你一个下标从 0 开始的字符串 word
。
一次操作中,你可以选择 word
中任意一个下标 i
,将 word[i]
修改成任意一个小写英文字母。
请你返回消除 word
中所有相邻 近似相等 字符的 最少 操作次数。
两个字符 a
和 b
如果满足 a == b
或者 a
和 b
在字母表中是相邻的,那么我们称它们是 近似相等 字符。
2. 示例
输入:word = "aaaaa" 输出:2 解释:我们将 word 变为 "acaca" ,该字符串没有相邻近似相等字符。 消除 word 中所有相邻近似相等字符最少需要 2 次操作。
示例 2:
输入:word = "abddez" 输出:2 解释:我们将 word 变为 "ybdoez" ,该字符串没有相邻近似相等字符。 消除 word 中所有相邻近似相等字符最少需要 2 次操作。
示例 3:
输入:word = "zyxyxyz" 输出:3 解释:我们将 word 变为 "zaxaxaz" ,该字符串没有相邻近似相等字符。 消除 word 中所有相邻近似相等字符最少需要 3 次操作
3. 思路
这题是一类动态规划的题目,根据题目中所说:相邻的字符是不能有近似(即ASCII码的差值不能低于1),那么我们可以这样:定义一个数组来保存当前长度字符串的结果。然后进行一个判断:
- 字符串长度等于1;这里可以直接返回0
- 字符串长度大于1;这里就要进行下一步
判断完后咱们又有一个疑问,如果我要更新当前字符串的结果状态,该怎么转换呢?我们要知道,假设当前索引是index,那么字符串中前index-1长度的结果肯定是局部最优的,那么我们考虑的状态转移肯定包含index-1这个子状态的;那么还有其它状态吗?有!我们要知道,我们的状态数组是一个一个往里面加的,碰到相似字符也只能是当前字符和上一个字符这种情况,那么此时我们就要更改这两个字符中的某一个,如果更改上一个字符,那么我们就需要考虑到倒数第2个状态:f(n-2),如果更改当前字符,那么我们就考虑上一个状态:f(n-1),因此我们的状态转移表达式为:
f(n) = min(f(n-1)+1,f(n-2)+1)
f(n-1) + 1 是 f(n-1)这个局部最优状态下更改当前字符;f(n-2) + 1 是f(n-2)这个局部最优状态下更改上一个字符。
4. 代码实现
class Solution:
def removeAlmostEqualCharacters(self, word: str) -> int:
result = [0,0] # 用于保存状态
length = len(word) # 获取字符串长度
# 如果长度为1,则直接返回0
if length == 1:
return 0
else:
# 从第2个字符开始遍历
for i in range(1,length):
# 如果当前字符和上一个字符不是近似字符,则直接使用上一次的状态,不需要更改字符
if abs(ord(word[i]) - ord(word[i-1])) > 1:
result.append(result[-1])
# 如果当前字符和上一个字符是近似字符,则需要状态转移
else:
# f(n) = min(f(n-2)+1,f(n-1)+1)
result.append(min(
result[-2] + 1, # 更改上一个字符
result[-1] + 1 # 更改当前字符
))
return result[-1] # 返回最后一个字符的状态值(即为整个字符串需要更改的最小次数)