下面题目是马海银(厥衡)大牛内推蚂蚁金服做的面试题。
源码已上传至我的GitHub:https://github.com/tangquanbin/structure
题目1:最小函数min()栈
1. 设计含最小函数min()、取出元素函数pop()、放入元素函数push()的栈AntMinStack,实现其中指定的方法
2. AntMinStack中数据存储使用Java原生的Stack,存储数据元素为int。请实现下面对应的方法,完善功能。
import java.util.Stack; /** * 1:最小函数min()栈 * * 1. 设计含最小函数min()、取出元素函数pop()、放入元素函数push()的栈AntMinStack,实现其中指定的方法 * 2. AntMinStack中数据存储使用Java原生的Stack,存储数据元素为int。请实现下面对应的方法,完善功能。 * @author tangquanbin * @date 2018/09/11 21:44 */ public class AntMinStack { /** * 真正存放数据栈 */ public static Stack<Integer> stack = new Stack<>(); /** * 存放最小数栈 */ public static Stack<Integer> minStack = new Stack<>(); /** * push 放入元素 * @param data */ public void push(int data) { stack.push(data); if (minStack.size()==0||data<minStack.peek()){ minStack.push(data); }else { minStack.push(minStack.peek()); } } /** * pop 推出元素 * @return * @throws Exception */ public int pop() throws Exception { minStack.pop(); return stack.pop(); } /** * min 最小函数,调用该函数,可直接返回当前AntMinStack的栈的最小值 * * @return * @throws Exception */ public int min() throws Exception { return minStack.peek(); } public static void main(String[] args){ AntMinStack antMinStack = new AntMinStack(); antMinStack.push(2); antMinStack.push(1); antMinStack.push(8); antMinStack.push(9); antMinStack.push(1); try { System.out.println("最小值:"+antMinStack.min()); antMinStack.pop(); antMinStack.pop(); System.out.println("最小值:"+antMinStack.min()); } catch (Exception e) { e.printStackTrace(); } }
题目2:算数表达式
设计数据结构与算法,计算算数表达式,需要支持
-
基本计算,加减乘除,满足计算优先级 例如输入 3*0+3+8+9*1 输出20
-
括号,支持括号,例如输入 3+(3-0)*2 输出 9
-
假设所有的数字均为整数,无需考虑精度问题
要求:
1. 输入的表达式是字符串类型String。
2. 对于操作数要求不止一位,这里对字符串里面解析出操作数有要求。需要有从表达式里面解析出完整操作数的能力。
3. 代码结构要求具备一定的面向对象原则,能够定义出表达式,操作数,运算符等对象。
4. 提供基本的测试。
/** * 表达式 * * @author tangquanbin * @date 2018/9/12 19:42 */ public class Expression { /** * 表达式名字 */ private String name; /** * 表达式 */ private String expressionStr; /** * 表达式值 */ private int value; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getExpressionStr() { return expressionStr; } public void setExpressionStr(String expressionStr) { this.expressionStr = expressionStr; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
/** * 操作数 * @author tangquanbin * @date 2018/9/12 19:43 */ public class Operand { /** * 操作数值 */ private Integer operandValue; public Integer getOperandValue() { return operandValue; } public void setOperandValue(Integer operandValue) { this.operandValue = operandValue; } }
/** * 运算符 * * @author tangquanbin * @date 2018/9/12 19:43 */ public class Operator { /** * 运算符符号 */ private char operatorName; public char getOperatorName() { return operatorName; } public void setOperatorName(char operatorName) { this.operatorName = operatorName; } }
import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * 计算工具 * @author tangquanbin * @date 2018/9/13 14:35 */ public class CalculatorUtil { /** * 加 */ private static final String ADD = "+"; /** * 减 */ private static final String SUBTRACT = "-"; /** * 乘 */ private static final String MULTIPLICATION = "*"; /** * 除 */ private static final String DIVISION = "/"; /** * 左括号 */ private static final String LEFT_PARENTHESIS = "("; /** * 右括号 */ private static final String RIGHT_PARENTHESIS = ")"; /** * * 提供给外部的计算方法 * * @param expression 后缀表达式 * @return 计算结果 */ public static int calculation(Expression expression) throws Exception { List<String> list = getPostfix(expression); Stack<Integer> calculationStack = new Stack<>(); Integer operandRight; Integer operandLeft; for (String item : list) { if (ADD.equals(item)) { operandRight = calculationStack.pop(); operandLeft = calculationStack.pop(); calculationStack.push(operandLeft + operandRight); } else if (SUBTRACT.equals(item)) { operandRight = calculationStack.pop(); operandLeft = calculationStack.pop(); calculationStack.push(operandLeft - operandRight); } else if (MULTIPLICATION.equals(item)) { operandRight = calculationStack.pop(); operandLeft = calculationStack.pop(); calculationStack.push(operandLeft * operandRight); } else if (DIVISION.equals(item)) { operandRight = calculationStack.pop(); operandLeft = calculationStack.pop(); calculationStack.push(operandLeft / operandRight); } else { calculationStack.push(Integer.parseInt(item)); } } return calculationStack.pop(); } /** * 判断字符为运算符(+,-,*,/) * * @param c 输入字符 * @return */ private static boolean isOperator(char c) { return ADD.equals(String.valueOf(c)) || SUBTRACT.equals(String.valueOf(c)) || MULTIPLICATION.equals(String.valueOf(c)) || DIVISION.equals(String.valueOf(c)); } /** * 返回的是运算符的优先级 * * @param operator * @return */ private static int priority(Operator operator) { char operatorName = operator.getOperatorName(); if (ADD.equals(String.valueOf(operatorName)) || SUBTRACT.equals(String.valueOf(operatorName))) { return 1; } else if (MULTIPLICATION.equals(String.valueOf(operatorName)) || DIVISION.equals(String.valueOf(operatorName))) { return 2; } else { return 0; } } /** * 通过表达式获得后缀表达式 * * @param expression * @return */ private static List<String> getPostfix(Expression expression) throws Exception { /** * 操作符栈 */ Stack<Operator> operatorStack = new Stack<>(); /** * 存放后缀表达式 */ List<String> operandList = new ArrayList<>(); String expressionStr = expression.getExpressionStr(); for (int i = 0; i < expressionStr.length(); i++) { char oneChar = expressionStr.charAt(i); Operator operator = new Operator(); operator.setOperatorName(oneChar); //遇到操作数:直接输出(添加到后缀表达式中) if (Character.isDigit(oneChar)) { int num = oneChar - '0'; while (i + 1 < expressionStr.length() && Character.isDigit(expressionStr.charAt(i + 1))) { num = num * 10 + expressionStr.charAt(i + 1) - '0'; i++; } operandList.add(String.valueOf(num)); } else if (LEFT_PARENTHESIS.equals(String.valueOf(oneChar))) { //遇到左括号:将其入栈 operatorStack.push(operator); } else if (RIGHT_PARENTHESIS.equals(String.valueOf(oneChar))) { //遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。 while (!LEFT_PARENTHESIS.equals(String.valueOf(operatorStack.peek().getOperatorName()))) { operandList.add(String.valueOf(operatorStack.pop().getOperatorName())); } //然后弹出左括号 operatorStack.pop(); } else if (isOperator(oneChar)) { //遇到运算符 //栈为空时,直接入栈 if (operatorStack.isEmpty()) { operatorStack.push(operator); } else { // 如果读入的操作符为非")"且优先级比栈顶元素的优先级高或一样 if (priority(operatorStack.peek()) < priority(operator)) { operatorStack.push(operator); } else if (priority(operatorStack.peek()) >= priority(operator)) { operandList.add(String.valueOf(operatorStack.pop().getOperatorName())); operatorStack.push(operator); } } } } //最终将栈中的元素依次出栈。 while (!operatorStack.isEmpty()) { operandList.add(String.valueOf(operatorStack.pop().getOperatorName())); } System.out.println(operandList); return operandList; } }
测试类
/** * @author tangquanbin * @date 2018/9/13 11:49 */ public class Test { public static void main(String[] args) { Expression expression = new Expression(); expression.setExpressionStr("4 +(13 - 5)"); try { System.out.println(CalculatorUtil.calculation(expression)); } catch (Exception e) { e.printStackTrace(); } } }
题目3:提供一个懒汉模式的单实例类实现,并满足如下要求:
1.考虑线程安全。
2.基于junit提供测试代码,模拟并发,测试线程安全性,给出对应的断言。
/** * 3:提供一个懒汉模式的单实例类实现,并满足如下要求: * 1.考虑线程安全。 * 2.基于junit提供测试代码,模拟并发,测试线程安全性,给出对应的断言。 * @author tangquanbin * @date 2018/9/12 19:04 */ public class Singleton { private Singleton(){ } public static Singleton getInstance(){ return SingletonHelper.instance; } /** * 静态内部内 */ private static class SingletonHelper{ private static final Singleton instance = new Singleton(); } }
Junit断言测试
import com.good.good.study.singleton.Singleton; import org.junit.Test; import java.util.concurrent.CountDownLatch; import static org.junit.Assert.assertEquals; /** * @author tangquanbin * @date 2018/9/13 15:01 */ public class JunitTest { private CountDownLatch latch = new CountDownLatch(3); @Test public void testSingleton(){ final String hashCode = String.valueOf(Singleton.getInstance().hashCode()); for (int i=0;i<200;i++) { Thread thread = new Thread() { @Override public void run() { assertEquals(hashCode,String.valueOf(Singleton.getInstance().hashCode())); } }; thread.start(); } try { latch.await(); // 主线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } }