Implement a basic calculator to evaluate a simple expression string.
The expression string contains only non-negative integers, +
, -
, *
, /
operators and empty spaces . The integer division should truncate toward zero.
You may assume that the given expression is always valid.
Some examples:
"3+2*2" = 7 " 3/2 " = 1 " 3+5 / 2 " = 5
Note: Do not use the eval
built-in library function.
看到计算表达式,就想到计算机可以顺序计算的后缀表达式表达式。所以本题可以分两个步骤解决。
1. 将表达式变为后缀表达式。主要是运算符压栈出栈顺序
2. 计算后缀表达式 so easy
注意计算表达式的时候后,要考虑到数字是10进制数,可能是多位
注意空格的特殊处理
注意单操作数处理
具体代码如下:
public static int calculate(String s) {
int res = 0;
Stack<Character> cal = new Stack<Character>();
int len = s.length();
StringBuffer bf = new StringBuffer();
List<Object> list = new ArrayList<Object>();
for (int i = 0; i <= len - 1; i++) {
char ch = s.charAt(i);
switch (ch) {
// 注意构建后缀表达式的时候,符号压栈一定要记得优先级高的或者同等优先级的都要先弹出
case ' ':
break;// 空格特殊处理
case '+':
int para1 = getInt(bf.toString());
list.add(para1);
bf = new StringBuffer();
while ((!cal.empty())
&& ((cal.peek() == '*') || cal.peek() == '/'
|| cal.peek() == '-' || cal.peek() == '+')) {
char c1 = cal.pop();
list.add(c1);
}
cal.push(ch);
break;
case '-':
int para2 = getInt(bf.toString());
list.add(para2);
bf = new StringBuffer();
while ((!cal.empty())
&& ((cal.peek() == '*') || cal.peek() == '/'
|| cal.peek() == '-' || cal.peek() == '+')) {
char c1 = cal.pop();
list.add(c1);
}
cal.push(ch);
break;
case '*':
int para3 = getInt(bf.toString());
list.add(para3);
bf = new StringBuffer();
while ((!cal.empty())
&& ((cal.peek() == '*') || cal.peek() == '/')) {
char c1 = cal.pop();
list.add(c1);
}
cal.push(ch);
break;
case '/':
int para4 = getInt(bf.toString());
list.add(para4);
bf = new StringBuffer();
while ((!cal.empty())
&& ((cal.peek() == '*') || cal.peek() == '/')) {
char c1 = cal.pop();
list.add(c1);
}
cal.push(ch);
break;
default:
bf.append(ch);
break;
}
}
// 循环处理完了,最后一个数字还未处理一定要处理
int para = getInt(bf.toString());
list.add(para);
// 记得把未处理完的运算符依次压栈
while (!cal.empty()) {
list.add(cal.pop());
}
res = calcu(list);
return res;
}
//给一个字符串,获取对应的数字值
public static int getInt(String s) {
int res = 0;
int len = s.length();
for (int i = 0; i < len; i++) {
char ch = s.charAt(i);
int index = (int) (ch - '0');
res += index*Math.pow(10, len - 1 - i);
}
return res;
}
/*计算后缀表达式的时候遇到数字压栈,遇到符号弹出两个数计算,计算完了的结果压栈*/
public static int calcu(List<Object> list)
{
if(list.size()<1) return 0;
Stack<Integer> cal = new Stack<Integer>();
for(int i=0;i<list.size();i++)
{
Object obj=list.get(i);
if(obj instanceof Integer)
{
cal.push((Integer) obj);
}
else if(obj instanceof Character)
{
char ch=(Character)obj;
/*栈是先进后出,注意操作数顺序*/
int b=cal.pop();
int a=cal.pop();
int fin=0;
if(ch=='+')
{
fin=a+b;
}
else if(ch=='-')
{
fin=a-b;
}
else if(ch=='*')
{
fin=a*b;
}
else if(ch=='/')
{
fin=a/b;
}
cal.push(fin);
}
}
if(!cal.empty())
return cal.pop();
else
//注意只有一个操作数的情况
return (Integer)list.get(0);
}
@Test
public void case1()
{
String s="3+2*2";
int actual=calculate(s);
int res=7;
Assert.assertEquals(res, actual);
}
@Test
public void case2()
{
String s="3/2";
int actual=calculate(s);
int res=1;
Assert.assertEquals(res, actual);
}
@Test
public void case3()
{
String s="3+5/2";
int actual=calculate(s);
int res=5;
Assert.assertEquals(res, actual);
}
@Test
public void case4()
{
String s="3-11/2";
int actual=calculate(s);
int res=-2;
Assert.assertEquals(res, actual);
}
@Test
public void case5()
{
String s="100000/1/2/3/4/5/6/7/8/9/10";
int actual=calculate(s);
int res=0;
Assert.assertEquals(res, actual);
}
@Test
public void case6()
{
String s=" 30";
int actual=calculate(s);
int res=30;
Assert.assertEquals(res, actual);
}
@Test
public void case7()
{
String s="1-1+1";
int actual=calculate(s);
int res=1;
Assert.assertEquals(res, actual);
}