有效的括号
我最开始AC的代码,遇到左括号就进栈,遇到右括号就判断栈是否为空,不为空栈顶元素是否匹配当前右括号,可以就出栈。最后判断栈是否为空,为空就证明全部匹配。
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
//左括号入栈
if (c == '(' || c == '[' || c =='{') {
stack.push(c);
} else if (c == ')' && !stack.isEmpty() && stack.peek() == '(') {//如果能匹配且栈不为空
stack.pop();
} else if (c == ']' && !stack.isEmpty() && stack.peek() == '[') {
stack.pop();
} else if (c == '}' && !stack.isEmpty() && stack.peek() == '{') {
stack.pop();
} else {
//可能出现还有右括号但是栈为空
//或者还有右括号但是不怕匹配
return false;
}
}
return stack.isEmpty();
}
}
题解的代码。思路差不多,这是每次遇到左括号就将对应的右括号入栈,
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(') {
stack.push(')');
} else if (c == '[') {
stack.push(']');
} else if (c == '{') {
stack.push('}');
} else if (stack.isEmpty() || c != stack.peek()) {
return false;
} else {
stack.pop();
}
}
return stack.isEmpty();
}
}
删除字符串中的所有相邻重复项
最开始AC的代码。思路很简单,将字符串中每个字符一一入栈,如果当前字符和栈顶字符相同,就将栈顶元素出栈,最后将在栈中的元素反转输出即可。
class Solution {
public String removeDuplicates(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (!stack.isEmpty() && c == stack.peek()) {
stack.pop();
continue;
}
stack.push(c);
}
StringBuffer sb = new StringBuffer();
while (!stack.isEmpty()) {
sb.append(stack.pop());
}
return sb.reverse().toString();
}
}
下面时题解的代码,这个是直接将字符串作为栈,可以省去将栈转换为字符串的操作
class Solution {
public String removeDuplicates(String s) {
// 将 res 当做栈
StringBuffer res = new StringBuffer();
// top为 res 的长度
int top = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// 当 top > 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
if (top >= 0 && res.charAt(top) == c) {
res.deleteCharAt(top);
top--;
// 否则,将该字符 入栈,同时top++
} else {
res.append(c);
top++;
}
}
return res.toString();
}
}
双指针的操作
class Solution {
public String removeDuplicates(String s) {
char[] ch = s.toCharArray();
int fast = 0;
int slow = 0;
while(fast < s.length()){
// 直接用fast指针覆盖slow指针的值
ch[slow] = ch[fast];
// 遇到前后相同值的,就跳过,即slow指针后退一步,下次循环就可以直接被覆盖掉了
if(slow > 0 && ch[slow] == ch[slow - 1]){
slow--;
}else{
slow++;
}
fast++;
}
return new String(ch,0,slow);
}
}
逆波兰表达式
最开始AC的代码,前缀表达式、中缀表达式、后缀表达式我在看大话数据结构时简单了解过。数据机构课上也学过,所以最基本的操作还是理解的。
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
Integer op1, op2;
for (String s : tokens) {
switch (s) {
case "+":
op1 = stack.pop();
op2 = stack.pop();
stack.push(op1 + op2);
break;
case "-":
op1 = stack.pop();
op2 = stack.pop();
//注意减法顺序,是后出的减去先出的
stack.push(op2 - op1);
break;
case "*":
op1 = stack.pop();
op2 = stack.pop();
stack.push(op1 * op2);
break;
case "/":
op1 = stack.pop();
op2 = stack.pop();
//注意触发顺序,和减法一样
stack.push(op2 / op1);
break;
default:
stack.push(Integer.parseInt(s));
break;
}
}
return stack.pop();
}
}
这是题解的代码,更加简洁。
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (String s : tokens) {
if ("+".equals(s)) { // leetcode 内置jdk的问题,不能使用==判断字符串是否相等
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}