栈的压入弹出序列
来源:剑指offer22
给定两个整数序列,第一个为栈的压入序列,判断第二个序列是否为栈的弹出序列。
思路:同时遍历两个序列,当第二个序列中的元素不等于第一个序列中元素时,判断栈顶元素是否等于当前元素,如是则弹出,第二个游标后移。若不是,将第一个序列当前元素入栈后,游标后移,循环判断。
eg: 123456 与 132465,压弹栈的顺序为
1,入栈,出栈
2,入栈
3,入栈,出栈
2,出栈
4,入栈,出栈
5,入栈
6,入栈
6,出栈
5,出栈
//此代码未检查,若有问题,欢迎提出^_^
public boolean IsPopOrder(int[] push, int[] pop){
if(push.length != pop.length) return false;
Deque<Integer> deque = new ArrayDeque<Integer>();
int i = 0, j = 0;
for(; i < push.length && j < push.length;){
if(push[i] == pop[j]){
i++;j++;
}
else if(!deque.isEmpty() && deque.peek().equals(pop[j])){
deque.pollLast();
j++;
}else deque.add(push[i++]);
}
while(j < push.length && !deque.isEmpty())
if(!deque.pollLast().equals(pop[j++])) return false;
return true;
}
后缀表达式求解
来源 https://leetcode.com/problems/evaluate-reverse-polish-notation/
Evaluate the value of an arithmetic expression in Reverse Polish Notation.
["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
后缀表达式求值
将操作数压栈,遇到操作符弹出操作数计算。
public int evalRPN(String[] tokens) {
Deque<Integer> deque = new ArrayDeque<Integer>();
for(int i = 0; i < tokens.length; i++){
String toch = tokens[i];
if(toch.equals("+")||toch.equals("-")||toch.equals("*")||toch.equals("/")){
int oper2 = deque.pollLast(), oper1 = deque.pollLast(), val;
switch(toch){
case "+": val = oper1 + oper2; break;
case "-": val = oper1 - oper2; break;
case "*": val = oper1 * oper2; break;
case "/": val = oper1 / oper2; break;
}
deque.add(val);
}else deque.add(atoi(toch));
}
return deque.pollLast();
}
括号匹配问题
1. Easy, 判断括号是否匹配
https://leetcode.com/problems/valid-parentheses/
Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’,determine if the input string is valid. The brackets must close in the correct order, “()” and “()[]{}” are all valid but “(]” and “([)]” are not.
思路:用栈存储来判断。在判断匹配时,利用()[]{}的ASCii码值关系进行判断相等。
public boolean isValid(String s){
char[] chstr = s.toCharArray();
Deque<Character> deque = new ArrayDeque<Character>();
for(int i = 0; i < chstr.length; i++){
if(deque.isEmpty() || (abs(deque.peekLast(), chstr[i])!= 1 && abs(deque.peekLast(), chstr[i])!=2))
deque.add(chstr[i]);
else deque.pollLast();
}
if(!deque.isEmpty()) return false;
else return true;
}
public int abs(char c1, char c2){
return c1 > c2 ? c1 - c2 : c2 - c1;
}
2. Hard, 判断最长匹配括号
https://leetcode.com/problems/longest-valid-parentheses/
Given a string containing just the characters ‘(’ and ‘)’,find the length of the longest valid (well-formed) parentheses substring.For “(()”, the longest valid parentheses substring is “()”, which has length = 2.Another example is “)()())”, where the longest valid parentheses substring is “()()”, which has length = 4.
思路:
保存两个值leftmost和longest分别记录下一个匹配括号链的最左边界和连续括号长度。当出现(时,将其压入栈中。当出现),判断栈中当前是否有元素。若没有,说明前一个匹配括号链已经断开,重置leftmost的值。若有,说明未断开链,更新longest的值。
如何更新longest的值呢,对于(和)都用其在数组中的Index来表示。如果括号链未断开,直接用)index-栈顶(index,即为当前括号链的长度(如果栈中没有元素,则减去leftmost),将此值与longest值做比较并更新。
public int longestValidParenthesesII(String s){
char[] chstr = s.toCharArray();
Deque<Integer> deque = new ArrayDeque<Integer>();
int longest = 0, leftmost = -1;
for(int i = 0; i < chstr.length; i++){
if(chstr[i] == '(') deque.add(i);
else if(deque.size() == 0) leftmost = i;
else{
deque.pollLast();
int tmp;
if(deque.size() == 0) tmp = leftmost;
else tmp = deque.peekLast();
longest = longest > (i - tmp) ? longest : (i - tmp);
}
}
return longest;
}
数制转化问题
思路:
数制转化问题可以利用乘法除法进行运算并用栈或者其他数据结构进行存储,但是更高效的是能用就用位运算来做。例如将十进制转为16、8、2进制,都可以运用位运算来做,这里贴出java.lang.Integer中进制转化代码供借鉴和学习~
private static String toUnsignedString(int i, int shift){//i为待转换的整数,shift为要转换的进制需要与的位数
char[] buf = new char[32];
int mask = (1 << shift)-1; //要每次与的值,16进制是1111(15),8进制是111(7),2进制是1(1)
int pos = 32;//从后向前
do{
buf[--pos] = i & mask;
i >>>= shift;
}while(i != 0);
return new String(buf, pos, (32-pos));//此处可以根据实际情况改写。
}
路径简化问题
来源:leetcode71 https://leetcode.com/problems/simplify-path/
Given an absolute path for a file (Unix-style), simplify it.
For example,
path = "/home/", => "/home"
path = "/a/./b/../../c/", => "/c"
Did you consider the case where path = "/../"? In this case, you should return "/".
Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/".
In this case, you should ignore redundant slashes and return "/home/foo".
思路:将串按照/切成一块一块的,不断将串块中的字符串压入栈,.没有操作,..连续弹出两个元素,最后弹出元素并拼接好。
public String simplifyPath(String path) {
Deque<String> deque = new ArrayDeque<String>();
int startslash = 0, endslash = 0;
while(endslash <= path.length()){
if(endslash == path.length() || path.charAt(endslash)=='/'){
if(endslash > startslash+1){
String sub = path.substring(startslash+1, endslash);
if(sub.equals("..")) {
if(deque.size()>=1) deque.pollLast();
}
else if(sub.equals("."));
else deque.add(sub);
}
startslash = endslash;
}
endslash++;
}
StringBuilder sb = new StringBuilder();
while(deque.size() != 0) sb.insert(0, "/" + deque.pollLast());
return sb.length() == 0 ? "/" : sb.toString();
}