今天继续学习栈与队列相关题目,今天两道题都是关于栈的。
LeetCode1047.删除字符串中所有相邻重复项
本题如果没有了解过栈这种数据结构,也没有做过相关题目,我觉得还是不太容易想到的。因为就算我昨天做过括号匹配的题目,看到这道题的时候,下意识仍然是能否用多层循环遍历来暴力破解。然后我想到这是栈与队列相关题目,仔细一琢磨,和括号匹配有点类似。括号匹配是左右括号做匹配,这个是相同字母做匹配,匹配成功后都将其删除。
具体做法是,遍历字符串的每一个字符,如果与栈顶元素相同,则栈顶元素出栈,反之,该字符入栈。最后栈中剩余元素即为删除所有相同项后的字符串,但是栈内元素出栈的话顺序会与预计结果相反,需要进一步操作来颠倒顺序。可以再借助栈或者集合,我用的是StringBuilder类进行拼接。
public static String removeDuplicates(String s){
Stack<Character> stack=new Stack<>();
for (int i = 0; i < s.length(); i++) {
if (!stack.isEmpty()) {
if (stack.peek()==s.charAt(i)){
stack.pop();
}else {
stack.push(s.charAt(i));
}
}else {
stack.push(s.charAt(i));
}
}
StringBuilder sb=new StringBuilder();
while (!stack.isEmpty()){
sb.insert(0,stack.pop());
}
return sb.toString();
}
LeetCode150.逆波兰表达式求值
逆波兰表达式也叫后缀表达式,这里是百度百科给的定义。在日常生活中数学表达式的写法是二叉树的中序遍历得到的顺序,而逆波兰式是后序遍历得到的结果。逆波兰式的好处是因为计算机使用了很多栈的内存结构,采取先进后出,后进先出的规则,所以使用这种表达式更利于计算机的阅读。
根据以上理论,再根据括号匹配和删除相同项两道题目,很容易想到用栈来解决问题,那么该如何正确使用栈来解决这道题呢?这道题第一时间可能会有所犹豫,因为括号匹配和删除相同项都是两两匹配,这道题其实是三个元素进行匹配,碰到运算符,出栈两个元素,这样的匹配方式。
具体逻辑是,使用一个栈来存储该表达式,如果是数字,则将其入栈,如果碰到运算符,将栈顶两个元素依次出栈后,根据运算符进行数学运算,将结果再次入栈,即一次匹配,两次出栈,一次入栈。
public static int evalRPN(String[] tokens){
Stack<String> stack=new Stack<>();
int result=0;
for (int i = 0; i < tokens.length; i++) {
if (!stack.isEmpty()){
if (tokens[i].equals("+")){
int temp1=Integer.parseInt(stack.pop());
int temp2=Integer.parseInt(stack.pop());
result=temp1+temp2;
stack.push(String.valueOf(result));
}else if (tokens[i].equals("-")){
int temp1=Integer.parseInt(stack.pop());
int temp2=Integer.parseInt(stack.pop());
result=temp2-temp1;
stack.push(String.valueOf(result));
}else if (tokens[i].equals("*")){
int temp1=Integer.parseInt(stack.pop());
int temp2=Integer.parseInt(stack.pop());
result=temp1*temp2;
stack.push(String.valueOf(result));
}else if (tokens[i].equals("/")){
int temp1=Integer.parseInt(stack.pop());
int temp2=Integer.parseInt(stack.pop());
result=temp2/temp1;
stack.push(String.valueOf(result));
} else {
stack.push(tokens[i]);
}
}else {
stack.push(tokens[i]);
}
}
return Integer.parseInt(stack.pop());
}
需要注意一共有三点。第一点,这两道题都需要注意,当栈为空时,不能进行出栈操作,否则会报错,所以出栈的操作都应在判断过栈不为空的情况下执行。第二点,加和乘的运算顺序无所谓,因为根据数学知识,有交换律可以将两个数字进行交换顺序。但是如果是减法和除法,需要注意其顺序,哪一个元素是被减(除)数,哪一个是减(除)数。距离如果栈内元素为(3,2,4,6),假设右边为栈顶,下一个字符是"-",那么应该是,4-6,而不是6-4,如果顺序错误,将会导致结果错误,这里要注意出栈的先后顺序和运算的顺序。
第三点,多个if的并列和ifelse的区别。