using System; using System.Collections.Generic; class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回表达式的值 * @param s string字符串 待计算的表达式 * @return int整型 */ Stack<Char> ops = new Stack<char>(); Stack<int> nums = new Stack<int>(); Dictionary<char, int> D = new Dictionary<char, int>(); public Solution() { D.Add('(', 1); D.Add('+', 3); D.Add('-', 3); D.Add(')', 4); D.Add('s', 5); D.Add('@', 0); //乘以10的运算 D.Add('*', 2); } public int solve(string s) { // write code here ops.Clear(); nums.Clear(); for (int i = 0; i < s.Length; i++) { if (i == s.Length - 1) handle(s[i], 's'); else handle(s[i], s[i + 1]); } while(nums.Count>1) { Shrink(); } return nums.Pop(); } public void handle(char c, char next) { if (c >= '0' && c <= '9') { //是连续两个数字 if (next >= '0' && next <= '9') { int newC = -1000; if (ops.Count > 0 && ops.Peek() == '@') { newC = Cal(nums.Pop(), c - '0', ops.Pop()); nums.Push(newC); ops.Push('@'); } else { nums.Push(c - '0'); ops.Push('@'); } return; } //不是连续两个数字 if (nums.Count > 0 && ops.Count > 0) { if (D[next] >= D[ops.Peek()] && ops.Peek()!='(') { int start = nums.Pop(); int end = c - '0'; char op = ops.Pop(); int num = Cal(start, end, op); nums.Push(num); while(ops.Count>0&& D[next]>=D[ops.Peek()] && nums.Count>=2 && ops.Peek()!='(') { Shrink(); } return; } } nums.Push(c - '0'); // ops.Push() return; } if (c == '+' || c == '-' || c == '*' || c == '(') { ops.Push(c); } if (c == ')') { //int start, end, num; //char op; while (ops.Peek() != '(') { //end = nums.Pop(); //op = ops.Pop(); //start = nums.Pop(); //num = Cal(start, end, op); //nums.Push(num); Shrink(); } ops.Pop(); } } private void Shrink() { int start, end, num; char op; end = nums.Pop(); op = ops.Pop(); start = nums.Pop(); num = Cal(start, end, op); nums.Push(num); } private int Cal(int s, int e, char op) { switch (op) { case '+': return s + e; case '-': return s - e; case '*': return s * e; case '@': return s * 10 + e; default: return int.MinValue; } } }
写的有点混乱,但是思路应该很容易理解:
1. 要定义非字母符号的优先级
2. 考虑到数字不是个位,因为这里添加了‘@’符号,如果一个数a后面仍然是数b,那么插入下一个数时,会取出上一个数进位,将1*10+b放入;但是如果首位时两个数字,那么第一个无法进位,这里表现为一个判断
3.每次输入数字时,会进行判断,如果数字后面的字符优先级不高于栈定符号的优先级,那么就进行运算:1+2+3,到2的时候,发现第二个加号优先级不高于1,故先将见面的计算出来,将数字入栈
4.如果后面的优先级高于栈顶的优先级 ,那么只能先将数字存入,后面在算 :例如 1+2*3 ,到2的时候只能先存入
5.考虑到括号存在,“("优先级高于任何算数,只能因”)“出现而成对销毁
6. shrink函数是收缩的意思,九世纪因为后面某个运算成功,导致前面一堆可以计算时,就先计算,例如 (1-(2-(10+3*4)))*5-6, 当最内的3*4计算完得到12入nums栈,但此时可以继续计算 10+12操作,这里就会调用Shrink函数,但是”(“运算符优先级高,不能拿出来运算
7.因为每次要传入当前字符和下一个字符,因此在最后一个字符遍历时,它的下一个字符手动设为”s',