相邻重复字母删除问题
问题描述
小M拿到了一个由小写字母组成的字符串 s。她发现可以进行一种操作:选择两个相邻且相同的字母并删除它们。她可以在 s 上反复进行此操作,直到无法再删除任何字母。
请返回最终处理完所有重复项删除操作后的字符串。可以保证返回的答案是唯一的。
测试样例
样例1:
输入:
s = "abbaca"
输出:'ca'
样例2:
输入:
s = "azxxzy"
输出:'ay'
样例3:
输入:
s = "a"
输出:'a'
问题分析
不难发现,题目的要求写的很清楚,就是给定一个字符串,让我们一直删除两个相邻且相同的字母,最终返回删除的结果。
这里就有一个很直接的思路,我们按照题目要求进行模拟。首先,遍历字符串s,如果发现s[i]==s[i+1],说明遇到了相邻且相同的字符,这时候我们直接删除s[i]和s[i+1]即可。但这样一次遍历下来可能不能将所有满足条件的字符都都删除。如样例1所示,第一次遍历只能删除连续的bb,但删除bb后的字符串又包含新的连续字符aa。说明只遍历一遍去删除连续字符是不妥当的。但是如果我们反复遍历呢?在遍历字符串循环的外面再添加一个新的while循环,我们一直删除字符串中连续的相同字符直到无法删除为止。
while :
is_end = true
for i in range(n-1):
if s[i]==s[i+1]:
delete s[i:i+2]
is_end = false
if is_end:
break
上述伪代码就是该思路的实现逻辑。
进一步分析
我们发现,单纯的使用while循环是十分耗时的。能否有一种方法可以只遍历一遍字符串就能得到结果呢?那就要用到一个新的数据结构:栈
栈的特点是先进后出,很符合题目的描述。我们可以让遍历到的字符一一进栈,如果遇到两个连续的相同字符,则他们一同出栈。如样例1所示,我们模拟栈的操作。
| 遍历的下标 | 该下标对应的字符 | 栈中数据 | 操作 |
|---|---|---|---|
| 0 | a | {a} | 进栈 |
| 1 | b | {a,b} | 进栈 |
| 2 | b | {a} | 出栈 |
| 3 | a | {} | 出栈 |
| 4 | c | {c} | 进栈 |
| 5 | a | {c,a} | 进栈 |
这样,我们最终再统计栈中剩余的元素即为返回的结果。
st = []
for i in range(n-1):
if s[i]==st[-1]: s.pop()
else: s.push(s[i])
return ''.join(st)
总结
实际上,在遇到这种成对出现消除操作时,首先想到的应该就是栈。比如经典的括号匹配问题,我们在思考问题的时候就可以想到如何用之前做过的题目来解答当前的问题。也就是如何将问题转化为可以被解决的问题,这是解决问题的通用手段。再一点,当一个问题过于复杂时,我们可以不用直接一口气将其解决,可以尝试解决其子问题或特殊情况,如第一步分析想到的直接遍历解法,虽然时间复杂度比较大,但是不失为一种方法可以解决问题。至于后面可以尝试采用数据结构去优化或者使用一些算法来解决我们朴素方法的问题。这种循序渐进的方式可以使得问题变得简单,也为最终的方法提供可解释性。