LeetCode:20. 有效的括号
问题描述
解决方案:
1.思路
- 借助栈先入后出特点。
- 建立栈 stack,遍历字符串 s 并按照算法流程一一判断;
- 遍历输入字符串
s
s
s,若遇到左括号入栈,遇到右括号时将对应栈顶左括号出栈,则遍历完所有括号后 stack 仍然为空;
- 建立哈希表 dic 构建左右括号对应关系:
k
e
y
key
key左括号,
v
a
l
u
e
value
value为 右括号;这样查询 两个括号是否对应只需
O
(
1
)
O(1)
O(1) 时间复杂度。
2.代码实现
class Solution {
private static final Map<Character, Character> map = new HashMap<Character, Character>() {
{
put('{', '}');
put('[', ']');
put('(', ')');
put('?', '?');
}
};
public boolean isValid(String s) {
if (s.length() > 0 && !map.containsKey(s.charAt(0)))
return false;
LinkedList<Character> stack = new LinkedList<Character>() {
{
add('?');
}
};
for (Character c : s.toCharArray()) {
if (map.containsKey(c))
stack.addLast(c);
else if (map.get(stack.removeLast()) != c)
return false;
}
return stack.size() == 1;
}
}
3.复杂度分析
- 时间复杂度:正确的括号组合需要遍历 1遍 s,故时间复杂度为
O
(
n
)
O(n)
O(n);
- 空间复杂度:哈希表和栈使用线性的空间大小。
4.注意
- 栈初始化的时候,初始化一个占位符
′
?
′
'?'
′?′,避免如果有括号多一个当弹出栈匹配的时候,栈为空,抛出错误(此时还没有去判断栈的大小);
LeetCode:1047. 删除字符串中的所有相邻重复项
问题描述
解决方案:
1.思路:
- 多组相邻重复项,我们无论先删除哪一项,都不会影响最终结果;
- 删除当前项是需要拿上一项出来对比的,所以我们需要用临时栈存放之前的内容;
- 当前项和栈顶一致,弹出栈顶抵消即可。若不一致,压入栈留存,供后续使用
2.代码实现
class Solution {
public String removeDuplicates(String s) {
StringBuffer stack = new StringBuffer();
int top = -1;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (top >= 0 && stack.charAt(top) == ch) {
stack.deleteCharAt(top);
--top;
} else {
stack.append(ch);
++top;
}
}
return stack.toString();
}
}
3.复杂度分析
- 时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n是字符串的长度。我们只需要遍历该字符串一次。
- 空间复杂度:
O
(
n
)
O(n)
O(n)。
4.疑惑思考
LeetCode:150. 逆波兰表达式求值
问题
解决方案:
1.思路:
2.代码实现
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<Integer>();
int n = tokens.length;
for (int i = 0; i < n; i++) {
String token = tokens[i];
if (isNumber(token)) {
stack.push(Integer.parseInt(token));
} else {
int num2 = stack.pop();
int num1 = stack.pop();
switch (token) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
default:
}
}
}
return stack.pop();
}
public boolean isNumber(String token) {
return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
}
}
3.复杂度分析
4.注意点
- 创建栈的时候,在这里我创建了一个新的、空的双端队列(基于LinkedList实现),并将其引用赋值给变量stack,这个双端队列专门用来存储整数。尽管名字叫stack,但在这里它是一个双端队列,不过由于双端队列允许像栈那样后进先出(LIFO)的操作,所以经常被当作栈来使用,特别是当需要同时支持栈和队列操作的灵活性时。