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;    }}


原创粉丝点击