问题描述
小M拿到了一个由小写字母组成的字符串 s。她发现可以进行一种操作:选择两个相邻且相同的字母并删除它们。她可以在 s 上反复进行此操作,直到无法再删除任何字母。
请返回最终处理完所有重复项删除操作后的字符串。可以保证返回的答案是唯一的。
测试样例
样例1:
输入:
s = "abbaca"
输出:'ca'
样例2:
输入:
s = "azxxzy"
输出:'ay'
样例3:
输入:
s = "a"
输出:'a'
题目分析
这道题的核心是通过删除相邻且相同的字母,反复操作直到字符串中不再有可以删除的相邻相同字母,并返回最终结果字符串。
题目保证结果是唯一的,这意味着只要按规则反复执行操作,最后的字符串不会因操作顺序不同而改变。
解题思路
1. 使用栈解决问题的原因
-
栈(Stack)是一个后进先出的数据结构,非常适合解决“相邻重复字符”的问题。
-
我们可以利用栈检查字符串的相邻字符:
- 如果当前字符与栈顶字符相同,则将栈顶字符弹出(删除一对相邻字符)。
- 如果不同,则将当前字符压入栈中。
2. 消除相邻重复的逻辑
- 当遍历完整个字符串后,栈中存放的字符就是处理后剩下的字符。
- 栈的后进先出特性意味着结果字符的顺序需要反转。
具体实现
import java.util.Stack;
public class Main {
public static String solution(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
// 如果栈不为空且栈顶元素与当前字符相同,弹出栈顶元素
if (!stack.isEmpty() && stack.peek() == c) {
stack.pop();
} else {
// 否则将当前字符推入栈中
stack.push(c);
}
}
// 构建结果字符串
StringBuilder result = new StringBuilder();
while (!stack.isEmpty()) {
result.append(stack.pop());
}
// 由于栈是后进先出,反转结果字符串
return result.reverse().toString();
}
public static void main(String[] args) {
System.out.println(solution("abbaca").equals("ca")); // 输出: true
System.out.println(solution("azxxzy").equals("ay")); // 输出: true
System.out.println(solution("a").equals("a")); // 输出: true
}
}
代码解析
主函数:solution(String s)
-
初始化栈
Stack<Character> stack = new Stack<>();创建一个栈来存储字符。
-
遍历字符串
for (char c : s.toCharArray()) {将字符串
s转为字符数组,逐一处理字符c。 -
判断栈顶字符是否与当前字符相同
if (!stack.isEmpty() && stack.peek() == c) { stack.pop(); // 栈顶元素与当前字符相同,删除 } else { stack.push(c); // 不同则压入栈中 }- 如果栈非空且栈顶字符与当前字符相同,则弹出栈顶字符,表示移除这对重复字符。
- 否则,将当前字符压入栈,表示它没有找到重复的相邻字符。
-
构建结果字符串
StringBuilder result = new StringBuilder(); while (!stack.isEmpty()) { result.append(stack.pop()); } return result.reverse().toString();- 将栈中剩余的字符弹出并拼接成字符串。
- 由于栈是后进先出的,最终结果需要反转。
测试样例
样例1:s = "abbaca"
-
初始字符串:
abbaca -
遍历并执行操作:
a压栈,栈:[a]b压栈,栈:[a, b]- 再次遇到
b,弹出栈顶b,栈:[a] a与栈顶a相同,弹出栈顶,栈:[]c压栈,栈:[c]a压栈,栈:[c, a]
-
栈中剩余字符为
ca(反转后仍为ca)。
样例2:s = "azxxzy"
-
初始字符串:
azxxzy -
遍历并执行操作:
a压栈,栈:[a]z压栈,栈:[a, z]x压栈,栈:[a, z, x]- 再次遇到
x,弹出栈顶x,栈:[a, z] z与栈顶z相同,弹出栈顶,栈:[a]y压栈,栈:[a, y]
-
栈中剩余字符为
ay(反转后仍为ay)。
样例3:s = "a"
-
初始字符串:
a -
遍历并执行操作:
a压栈,栈:[a]
-
栈中剩余字符为
a。
时间与空间复杂度分析
-
时间复杂度:
- 遍历字符串的时间复杂度为 O(n)O(n)O(n),其中 nnn 是字符串的长度。
- 栈操作(入栈和出栈)在单个字符上执行一次,总体仍为 O(n)O(n)O(n)。
- 因此,总时间复杂度为 O(n)O(n)O(n)。
-
空间复杂度:
- 最坏情况下,栈中可能存储字符串的所有字符,空间复杂度为 O(n)O(n)O(n)。
- 但在大多数情况下,栈中的字符少于输入字符数量,实际空间利用更优。
总结
这道题通过使用栈简洁地解决了重复字符消除问题,代码逻辑清晰,时间和空间复杂度都在合理范围内,是处理类似问题的经典方法。