相邻重复字母删除问题

47 阅读4分钟

问题描述

给定一个由小写字母组成的字符串 s,我们可以进行一种操作:选择两个相邻且相同的字母并删除它们。每次删除相邻的重复字母后,字符串可能会变得可以继续进行该操作。我们需要返回经过所有删除操作后的最终字符串。最终的结果保证唯一。

问题分析

此问题的核心是要找到一个合适的方式去处理重复的相邻字符。我们可以反复进行删除操作,直到没有两个相邻的字符相同。如何快速、高效地模拟这种操作呢?

对于每次删除相邻相同字符的操作,直觉上可以将这些相邻字符压入一个栈中。具体地,栈的顶端始终保存当前还没有被删除的字符。如果栈顶字符与当前字符相同,说明它们是一对相邻且相同的字符,我们就可以将栈顶字符删除,并继续处理下一个字符。

思路解析

  1. 使用栈来模拟字符的删除过程。栈能够高效地支持后进先出的特性,这非常适合本题的要求。
  2. 遍历字符串中的每个字符:
    • 如果栈不为空,且栈顶字符与当前字符相同,说明可以进行删除操作,弹出栈顶元素。
    • 如果栈为空或者栈顶字符与当前字符不同,则将当前字符压入栈中。
  3. 最终,栈中保存的就是无法进一步删除的字符。我们可以将栈中的元素拼接成字符串作为结果返回。

解法实现

通过上述思路,我们可以实现一个简洁且高效的解决方案:

def solution(s: str) -> str:
    # 使用栈来存储字符
    stack = []
    
    # 遍历字符串中的每一个字符
    for char in s:
        # 如果栈不为空且栈顶元素与当前字符相同,则弹出栈顶元素
        if stack and stack[-1] == char:
            stack.pop()
        else:
            # 否则,将当前字符压入栈中
            stack.append(char)
    
    # 将栈中的元素转换为字符串
    return ''.join(stack)

if __name__ == '__main__':
    print(solution(s="abbaca") == 'ca')
    print(solution(s="azxxzy") == 'ay')
    print(solution(s="a") == 'a')

代码详解

  1. 栈初始化:首先我们初始化一个空栈 stack,用来存储字符。
  2. 字符遍历:接着,我们遍历输入字符串 s 中的每一个字符 char
  3. 栈顶检查:在每次遍历过程中,如果栈非空且栈顶元素等于当前字符,我们就弹出栈顶元素(模拟删除)。如果栈顶元素与当前字符不同或栈为空,我们将当前字符压入栈中。
  4. 结果构建:最终,栈中的元素就是处理后的结果。我们使用 ''.join(stack) 将栈中的字符拼接成字符串并返回。

复杂度分析

  1. 时间复杂度:我们遍历字符串一次,每个字符最多入栈和出栈一次,因此时间复杂度是 O(n),其中 n 是字符串的长度。
  2. 空间复杂度:栈最多保存所有字符,因此空间复杂度为 O(n),其中 n 是字符串的长度。

样例分析

  • 样例1:输入 s = "abbaca"

    • 首先处理第一个字符 'a',将其压入栈。
    • 遇到 'b',将其压入栈。
    • 遇到第二个 'b',栈顶是 'b',所以将栈顶弹出,再将第二个 'b' 压入栈。
    • 遇到 'a',栈顶是 'a',所以将栈顶弹出。
    • 遇到 'c',将其压入栈。
    • 遇到 'a',将其压入栈。
      最终栈中是 ['c', 'a'],所以输出 'ca'
  • 样例2:输入 s = "azxxzy"

    • 处理过程类似,最终得到 'ay'
  • 样例3:输入 s = "a"

    • 只有一个字符,结果直接是 'a'

总结

这道题通过栈结构高效地模拟了相邻字符删除的操作。栈可以帮助我们快速判断相邻字符是否相同,并处理删除操作。通过遍历字符串,逐步构建最终的结果,我们能够在 O(n) 时间内完成该问题的解决。