LintCode堆栈题总结
来源:互联网 发布:java字符串去掉双引号 编辑:程序博客网 时间:2024/05/16 02:03
这篇是基于我之前的一篇文章的:LintCode数据结构题 那篇文章介绍了基本的堆栈实现以及一些基本的应用。现在来看一下更多的题目和应用来扩展一下对堆栈的实践。
575. Expression Expand
要求对表达式进行展开。比如 s = 3[2[ad]3[pf]]xyz, return adadpfpfpfadadpfpfpfadadpfpfpfxyz。这道题可以用一个栈Stack来解决。然后通过分支判断来处理不同的情况。需要注意的是数字可以是两位数三位数等等,所以要对数字进行整合。
从左往右扫描字符串,基本的逻辑如下:
1)如遇到数字,则把字符转换为数字
2)如遇到左括号,则把数字入栈
3)如遇到右括号,则把栈内的字符串拿出来做一个转换,再放回到栈中
4)如遇到普通的字符,则入栈
举个例子,假如字符串是2[2[a]2[p]]x,则转换过程如下图所示:
public class Solution { /** * @param s an expression includes numbers, letters and brackets * @return a string */ public String expressionExpand(String s) { Stack<String> stack = new Stack<String>(); int number = 0; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (Character.isDigit(c)) { number = number * 10 + (c - '0'); } else if (c == '[') { stack.push(number + ""); number = 0; } else if (c == ']') { String toAdd = popStack(stack); int count = Integer.parseInt(stack.pop()); for (int j = 0; j < count; j++) { stack.push(toAdd); } } else { stack.push(c + ""); } } return popStack(stack); } public String popStack(Stack<String> stack) { Stack<String> buffer = new Stack<String>(); while (!stack.isEmpty() && !Character.isDigit(stack.peek().charAt(0))) { buffer.push(stack.pop()); } StringBuilder sb = new StringBuilder(); while (!buffer.isEmpty()) { sb.append(buffer.pop()); } return sb.toString(); }}
367. Expression Tree Build
中缀表达式来构建表达式树,维基百科上有关于后缀表达式构建表达式树的算法:https://en.wikipedia.org/wiki/Binary_expression_tree 不过那个就简单很多。中缀建树就要难很多,启发于如下算法:http://www.cnblogs.com/deepblueme/p/4779514.html
我们需要用2个栈来解决,一个栈data用于存数字,一个栈op用于存操作符。从左往右扫描中缀表达式字符串:
1)若遇到数字,则new一个节点,存到data栈里面
2)若遇到左括号(,则new一个节点,存到op栈里面
3)若遇到+-,若op栈有运算符的话(不是左括号)话,那就循环的把op栈顶运算符拿出来,把data栈的2个数字拿出来,凑成一个树,然后压回data栈。循环完后,再把遇到的+-压入op栈。
4)若遇到*/,若op栈有运算符的话(不是*/)话,那就循环的把op栈顶运算符拿出来,把data栈的2个数字拿出来,凑成一个树,然后压回data栈。循环完后,再把遇到的*/压入op栈。
5)若遇到右括号,若op栈顶的运算符不是左括号的话,那就循环的把op栈顶运算符拿出来,把data栈的2个数字拿出来,凑成一个树,然后压回data栈。直到遇到左括号,然后把左括号pop出来。
有个小技巧就是可以在纸上画2个栈来模拟一下整个流程,这样就会清晰很多。不必死记硬背,随便拿出一个例子,然后onsite的时候拿出白板画一下模拟一下流程。思路整理顺畅后,代码自然就水到渠成了。
/** * Definition of ExpressionTreeNode: * public class ExpressionTreeNode { * public String symbol; * public ExpressionTreeNode left, right; * public ExpressionTreeNode(String symbol) { * this.symbol = symbol; * this.left = this.right = null; * } * } */public class Solution { /** * @param expression: A string array * @return: The root of expression tree */ public ExpressionTreeNode build(String[] expression) { Stack<ExpressionTreeNode> data = new Stack<ExpressionTreeNode>(); Stack<ExpressionTreeNode> op = new Stack<ExpressionTreeNode>(); for (String s : expression) { if (Character.isDigit(s.charAt(0))) { data.push(new ExpressionTreeNode(s)); } else if (s.equals("(")) { op.push(new ExpressionTreeNode(s)); // +-优先级很低,需要给其他操作符让路 } else if (s.equals("+") || s.equals("-")) { while (!op.isEmpty() && !op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); // */只需要给同级别的让路 } else if (s.equals("*") || s.equals("/")) { while (!op.isEmpty() && (op.peek().symbol.equals("*") || op.peek().symbol.equals("/"))) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); } else if (s.equals(")")) { while (!op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.pop(); } } // 操作符栈还有内容 while (!op.isEmpty()) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } if (data.isEmpty()) { return null; } return data.pop(); }}
368. Expression Evaluation
对表达式进行求值,几乎跟上题的代码一模一样,思路也是类似的。不再赘述了。反正也是用2个栈来解决,画画图就能理解了:
public class Solution { /** * @param expression: an array of strings; * @return: an integer */ public int calc(String op, String a, String b) { int x = Integer.parseInt(a); int y = Integer.parseInt(b); if (op.equals("*")) { return x * y; } else if (op.equals("/")) { return x / y; } else if (op.equals("+")) { return x + y; } else if (op.equals("-")) { return x - y; } return 0; } public int evaluateExpression(String[] expression) { Stack<String> data = new Stack<String>(); Stack<String> op = new Stack<String>(); for (String s: expression) { if (Character.isDigit(s.charAt(0))) { data.push(s); } else if (s.equals("(")) { op.push(s); } else if (s.equals("+") || s.equals("-")) { while (!op.isEmpty() && !op.peek().equals("(")) { String operator = op.pop(); String b = data.pop(); String a = data.pop(); String res = calc(operator, a, b) + ""; data.push(res); } op.push(s); } else if (s.equals("*") || s.equals("/")) { while (!op.isEmpty() && (op.peek().equals("*") || op.peek().equals("/"))) { String operator = op.pop(); String b = data.pop(); String a = data.pop(); String res = calc(operator, a, b) + ""; data.push(res); } op.push(s); } else if (s.equals(")")) { while (!op.isEmpty() && !op.peek().equals("(")) { String operator = op.pop(); String b = data.pop(); String a = data.pop(); String res = calc(operator, a, b) + ""; data.push(res); } op.pop(); } } while (!op.isEmpty()) { String operator = op.pop(); String b = data.pop(); String a = data.pop(); String res = calc(operator, a, b) + ""; data.push(res); } if (data.isEmpty()) { return 0; } return Integer.parseInt(data.pop()); }};
369. Convert Expression to Polish Notation
把一个表达式转换为波兰表达式,其实思路很简单,就是先把他建立成一棵表达式树,建树可以用上面拿到build expression tree的代码,然后再利用先序遍历整棵树就能得到答案了:
class ExpressionTreeNode { public String symbol; public ExpressionTreeNode left, right; public ExpressionTreeNode(String symbol) { this.symbol = symbol; this.left = this.right = null; } }public class Solution { /** * @param expression: A string array * @return: The Polish notation of this expression */ public ExpressionTreeNode build(String[] expression) { Stack<ExpressionTreeNode> data = new Stack<ExpressionTreeNode>(); Stack<ExpressionTreeNode> op = new Stack<ExpressionTreeNode>(); for (String s : expression) { if (Character.isDigit(s.charAt(0))) { data.push(new ExpressionTreeNode(s)); } else if (s.equals("(")) { op.push(new ExpressionTreeNode(s)); // +-优先级很低,需要给其他操作符让路 } else if (s.equals("+") || s.equals("-")) { while (!op.isEmpty() && !op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); // */只需要给同级别的让路 } else if (s.equals("*") || s.equals("/")) { while (!op.isEmpty() && (op.peek().symbol.equals("*") || op.peek().symbol.equals("/"))) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); } else if (s.equals(")")) { while (!op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.pop(); } } // 操作符栈还有内容 while (!op.isEmpty()) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } if (data.isEmpty()) { return null; } return data.pop(); } public void preTraversal(ArrayList<String> res, ExpressionTreeNode root) { if (root != null) { res.add(root.symbol); preTraversal(res, root.left); preTraversal(res, root.right); } } public ArrayList<String> convertToPN(String[] expression) { ExpressionTreeNode root = build(expression); ArrayList<String> res = new ArrayList<String>(); preTraversal(res, root); return res; }}
370. Convert Expression to Reverse Polish Notation
把一个表达式转换为逆波兰表达式,其实思路很简单,就是先把他建立成一棵表达式树,建树可以用上面拿到build expression tree的代码,然后再利用后序遍历整棵树就能得到答案了:
class ExpressionTreeNode { public String symbol; public ExpressionTreeNode left, right; public ExpressionTreeNode(String symbol) { this.symbol = symbol; this.left = this.right = null; } }public class Solution { /** * @param expression: A string array * @return: The Reverse Polish notation of this expression */ public ExpressionTreeNode build(String[] expression) { Stack<ExpressionTreeNode> data = new Stack<ExpressionTreeNode>(); Stack<ExpressionTreeNode> op = new Stack<ExpressionTreeNode>(); for (String s : expression) { if (Character.isDigit(s.charAt(0))) { data.push(new ExpressionTreeNode(s)); } else if (s.equals("(")) { op.push(new ExpressionTreeNode(s)); // +-优先级很低,需要给其他操作符让路 } else if (s.equals("+") || s.equals("-")) { while (!op.isEmpty() && !op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); // */只需要给同级别的让路 } else if (s.equals("*") || s.equals("/")) { while (!op.isEmpty() && (op.peek().symbol.equals("*") || op.peek().symbol.equals("/"))) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.push(new ExpressionTreeNode(s)); } else if (s.equals(")")) { while (!op.peek().symbol.equals("(")) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } op.pop(); } } // 操作符栈还有内容 while (!op.isEmpty()) { ExpressionTreeNode node = op.pop(); ExpressionTreeNode a = data.pop(); ExpressionTreeNode b = data.pop(); node.right = a; node.left = b; data.push(node); } if (data.isEmpty()) { return null; } return data.pop(); } public void postTraversal(ArrayList<String> res, ExpressionTreeNode root) { if (root != null) { postTraversal(res, root.left); postTraversal(res, root.right); res.add(root.symbol); } } public ArrayList<String> convertToRPN(String[] expression) { ExpressionTreeNode root = build(expression); ArrayList<String> res = new ArrayList<String>(); postTraversal(res, root); return res; }}
- LintCode堆栈题总结
- LintCode数组题总结
- LintCode数据结构题总结
- LintCode字符串题总结
- LintCode排序题总结
- LintCode图论&搜索题总结
- LintCode位运算题总结
- LintCode二分查找题总结
- LintCode贪心法题总结
- LintCode双指针题总结
- LintCode动态规划题总结
- lintcode做题总结, Sept 15
- lintcode做题总结, Sept 16
- lintcode做题总结, Sept 18
- lintcode做题总结, Sept 30
- lintcode做题总结, Oct 01
- lintcode做题总结, Oct 05
- lintcode做题总结, Oct 07
- 素材 图论-节点的度
- js实现数据绑定
- 欢迎使用CSDN-markdown编辑器
- Double类型两个数不能用双等号判断是否相等
- 查看linux版本
- LintCode堆栈题总结
- 自学Java之Java编程(编写Java servlet和Java server)(021day)
- bp神经网络及matlab实现
- servletContext
- Keil 软件中运行程序时system viewer 不显示
- Liferay 7.0 修改service.xml后如何让portal重新执行tables.sql
- ntp时间同步简介
- linux scp 文件传输
- 解决货币精度问题(NSDecimalNumber)