zoukankan      html  css  js  c++  java
  • 224. Basic Calculator + 227. Basic Calculator II

    ▶ 两个四则表达式运算的题目,第 770 题 Basic Calculator IV 带符号计算不会做 Orz,第 772 题 Basic Calculator III 要收费 Orz。

    ▶ 自己的全能版代码,28 ms,采用表达式中缀转后缀,然后利用栈来计算。支持加减乘除幂模,一模一样的代码刷掉了这两题,就是效率比较低,28 ms

      1 class Solution
      2 {
      3 public:
      4     int calculate(string s)//计算器,输入表达式,输出计算结果
      5     {
      6         string out;
      7         mid_to_last(s, out);
      8         return calculate_last(out);
      9     }
     10 private:
     11     int power(int a, int b)// 整数幂运算,a^b
     12     {
     13         int output;
     14         for (output = 1; b > 0; a *= a, b >>= 1)
     15         {
     16             if (b & 1)
     17                 output *= a;
     18         }
     19         return output;
     20     }
     21     int numread(const string & in, int start, string & output)//读取字符串数字,返回包括前导空白的数字长度
     22     {
     23         int i, blankLen;
     24         for (i = start, blankLen = 0, output = ""; in[i] == ' '; i++, blankLen++);// 跳过前导空白
     25         if (in[i] == '-')                           // -3
     26             i++;
     27         else if (in[i] == '+')                      // +3
     28             i++, blankLen++;
     29         if (in[i]<'0' || in[i]>'9')                 // 不是数字
     30             return 0;
     31         for (; in[i] >= '0' && in[i] <= '9'; i++);  // 寻找有效字符末尾
     32         output = in.substr(start + blankLen, i - start - blankLen);       
     33         return blankLen + output.size();
     34     }
     35     int rankSign(char c)//规定运算等级
     36     {
     37         switch (c)
     38         {
     39         case '':
     40             return -1;
     41         case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
     42             return 0;
     43         case '(':case ')':
     44             return 1;
     45         case '+':case '-':
     46             return 2;
     47         case '*':case '/':case '%':
     48             return 3;
     49         case '^':
     50             return 4;
     51         default:
     52             return -2;
     53         }
     54     }
     55     bool mid_to_last(const string & in, string & out)//表达式中缀转后缀
     56     {
     57         int pin, len;
     58         string tempStr;
     59         stack<char> sym;
     60         for (out = "", pin = 0; pin < in.size() && in[pin] != ''; pin++)
     61         {
     62             for (; in[pin] == ' '; pin++);              // 处理间隔空格
     63             for (; in[pin] == '('; sym.push(in[pin++]));// 连续的 '(' 压栈
     64   
     65             assert(len = numread(in, pin, tempStr));    // 读数字到 tmp 中            
     66             pin += len;                                 //向后跳位
     67             out += tempStr + ' ';                       // 读取的字符串输出到 out 中
     68 
     69             for (; in[pin] == ' '; pin++);              // 处理间隔空格
     70             for (; in[pin] == ')'; pin++, sym.pop())    // 遇到 ')',把栈中最近一个 '(' 之后的部分吐空,最后把 '(' 也吐掉
     71                 for (; sym.top() != '('; out += sym.top(), out += ' ', sym.pop());                    
     72 
     73             for (; in[pin] == ' '; pin++);              // 处理间隔空格
     74             if (in[pin] == '')            //表达式已空,正常结束,把栈吐空,结束
     75             {
     76                 for (; !sym.empty(); out += sym.top(), out += ' ', sym.pop());
     77                 return true;
     78             }
     79 
     80             if (sym.empty() || rankSign(in[pin]) > rankSign(sym.top()))         //空栈或表达式中算符等级高,压栈
     81                 sym.push(in[pin]);
     82             else
     83             {
     84                 for (; !sym.empty() && rankSign(in[pin]) <= rankSign(sym.top());) //吐到栈中算符等级小于表达式中字符为止
     85                     out += sym.top(), out += ' ', sym.pop();
     86                 sym.push(in[pin]);
     87             }
     88         }
     89         return false;                       // 表达式在错误的地方结束,报错
     90     }
     91     int calculate_last(const string & in)//输入后缀表达式计算
     92     {        
     93         int pin, len, tempNum;
     94         string tempStr;
     95         stack<int> number;        
     96         for (pin = 0; pin<in.size() && in[pin] != '';)// 连着字符和空白一起跳过去
     97         {                        
     98             // 取数字                                               
     99             if(len = numread(in, pin, tempStr))
    100             {
    101                 number.push(atoi(tempStr.c_str()));
    102                 pin += len + 1;
    103                 continue;
    104             }
    105             // 处理算符
    106             tempNum = number.top(), number.pop();
    107             assert(!number.empty());                // 缺少第二个参与运算的数字
    108             switch (in[pin])
    109             {
    110             case '+': tempNum = number.top() + tempNum; break;
    111             case '-': tempNum = number.top() - tempNum; break;
    112             case '*': tempNum = number.top() * tempNum; break;                            
    113             case '/': assert(tempNum), tempNum = number.top() / tempNum; break;             // 检查分母非零
    114             case '%': assert(tempNum), tempNum = number.top() % tempNum; break;             // 检查模数非零
    115             case '^': assert(tempNum >= 0), tempNum = power(number.top(), tempNum); break;  // 检查指数非负
    116             default:
    117                 assert(false);                      // 混入了其他符号
    118             }
    119             number.pop(), number.push(tempNum);
    120             pin += 2;
    121         }
    122         assert(!(number.empty() || number.size() > 1));// 栈空或者栈中有不止一个元素
    123         return number.top();
    124     }
    125 };

    ▶ 第 224 题,表达式仅含加减法,支持小括号

    ● 大佬的代码,13 ms,注意到只含 '+ - ( )' 的表达式可以完全去括号,然后从左向右依次计算,用一个变量 sign 记录当前数字在去括号过程中引入的附加符号

     1 class Solution
     2 {
     3 public:
     4     int calculate(string s)
     5     {
     6         stack<int> st;
     7         int i, res, sign, num;
     8         for (i = res = 0, sign = 1; i < s.size();)
     9         {
    10             switch (s[i])
    11             {
    12             case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
    13             {
    14                 for (num = 0; i < s.size() && s[i] >= '0' && s[i] <= '9'; num = (10 * num) + s[i] - '0', i++);
    15                 res += (sign * num);
    16                 break;
    17             }
    18             case ' ':
    19                 for (; i < s.size() && s[i] == ' '; i++); break;
    20             case '(':
    21                 st.push(res), st.push(sign), res = 0, sign = 1, i++; break;
    22             case ')':
    23                 res = res * st.top(), st.pop(), res += st.top(), st.pop(), i++; break;
    24             default:
    25                 sign = 44 - s[i], i++; break; // 44 - s[i] 等价于 (s[i] == '+') ? 1 : -1,因为 '+' == 43,'-' == 45
    26             }
    27         }
    28         return res;
    29     }
    30 };

    ▶ 第227 题,表达式含加减乘除,没有小括号

    ● 大佬的代码,13 ms,使用栈

     1 class Solution
     2 {
     3 public:
     4     int calculate(string s)
     5     {
     6         const int len = s.size();
     7         stack<int> st;
     8         int i, num, temp;
     9         char sign;
    10         for (i = num = 0, sign = '+'; i < len; i++)
    11         {
    12             if (s[i] >= '0' && s[i] <= '9')
    13                 num = num * 10 + s[i] - '0';            
    14             if ((s[i] < '0' || s[i] > '9') && s[i] != ' ' || i == len - 1)                
    15             {
    16                 if (sign == '-')
    17                     st.push(-num);
    18                 else if (sign == '+')
    19                     st.push(num);
    20                 else if (sign == '*')
    21                     temp = st.top(), st.pop(), st.push(temp * num);
    22                 else if (sign == '/')
    23                     temp = st.top(), st.pop(), st.push(temp / num);
    24                 sign = s[i];
    25                 num = 0;
    26             }
    27         }        
    28         for (temp = 0; !st.empty(); temp += st.top(), st.pop());
    29         return temp;
    30     }
    31 };

    ● 大佬的代码,12 ms,与上一个方法算法相同,不使用栈

     1 class Solution
     2 {
     3 public:
     4     void trim(string & s)
     5     {
     6         int index = 0;
     7         if (!s.empty())
     8             for (; (index = s.find(' ', index)) != string::npos; s.erase(index, 1));
     9     }
    10     int calculate(string s)
    11     {
    12         trim(s);        // 去掉所有空格,原 Java 代码:s = s.trim().replaceAll(" +", "");
    13         int length = s.size();
    14         int i, res;
    15         long preVal, curVal;
    16         char sign;
    17         for (i = res = preVal = 0, sign = '+'; i < length;)
    18         {
    19             for (curVal = 0; i < length && s[i] >= '0' && s[i] <= '9'; i++)
    20                 curVal = curVal * 10 + (s[i] - '0');
    21             if (sign == '+')
    22                 res += preVal, preVal = curVal; 
    23             else if (sign == '-')
    24                 res += preVal, preVal = -curVal
    25             else if (sign == '*')
    26                 preVal = preVal * curVal;
    27             else if (sign == '/')
    28                 preVal = preVal / curVal;
    29             if (i < length)
    30                 sign = s[i], i++;
    31         }
    32         res += preVal;
    33         return res;
    34     }
    35 };

    ● 大佬的方法,18 ms,三步走战略,先提取 token 替换符号,再计算乘除法,最后计算加减法

     1 class Solution
     2 {
     3 public:
     4     int calculate(string s)
     5     {
     6         if (s.size() == 0) 
     7             return 0;
     8         vector<int> exp, exp1;
     9 
    10         bool isLastDig = false;
    11         int i, curIdx, val, last, res;
    12         for (i = curIdx = val = 0; i < s.length(); i++)// 第一轮 string 转为 vector<int> 类型的 token,包括计算符
    13         {
    14             if (s[i] == ' ')
    15                 continue;
    16             val = s[i];
    17             if (val >= '0' && val <= '9')
    18             {
    19                 if (isLastDig)
    20                     exp[curIdx] = exp[curIdx] * 10 + (int)(val - '0');
    21                 else
    22                 {
    23                     isLastDig = true;
    24                     exp.push_back(val - '0');
    25                 }
    26             }
    27             else
    28             {
    29                 isLastDig = false;
    30                 if (s[i] == '-')      // +-*/ 分别用 -2,-1,-3,-4表示
    31                     exp.push_back(-1);
    32                 else if (s[i] == '+')  
    33                     exp.push_back(-2);
    34                 else if (s[i] == '*') 
    35                     exp.push_back(-3);
    36                 else if (s[i] == '/') 
    37                     exp.push_back(-4);
    38                 curIdx += 2;
    39             }
    40         }
    41         for (i = 0; i < exp.size(); i++)// 第二轮,进行乘除运算
    42         {
    43             if (exp[i] == -3)
    44             {
    45                 last = exp1.back();
    46                 exp1.pop_back();
    47                 exp1.push_back(last * exp[i + 1]);
    48                 i++;
    49             }
    50             else if (exp[i] == -4)
    51             {
    52                 last = exp1.back();
    53                 exp1.pop_back();
    54                 exp1.push_back(last / exp[i + 1]);
    55                 i++;
    56             }
    57             else
    58                 exp1.push_back(exp[i]);
    59         }
    60         if (exp1.size() == 1)// 只有乘除法的表达式,已经算完了
    61             return exp1[0];
    62         for (i = 1, res = exp1[0]; i < exp1.size(); i++)// 第三轮,进行加减运算
    63         {
    64             if (exp1[i] == -1)
    65                 res -= exp1[i + 1];
    66             else if (exp1[i] == -2)
    67                 res += exp1[i + 1];
    68         }
    69         return res;
    70     }
    71 };

    ● 大佬的神奇方法,19 ms,可能是 VS2015 支持的 C++ 版本低,暂不支持编译

     1 class Solution
     2 {
     3 public:
     4     int calculate(string s)
     5     {
     6         istringstream in('+' + s + '+');
     7         long long total = 0, term = 0, n;
     8         char op;
     9         while (in >> op)
    10         {
    11             if (op == '+' || op == '-')
    12             {
    13                 total += term;
    14                 in >> term;
    15                 term *= 44 - op;
    16             }
    17             else
    18             {
    19                 in >> n;
    20                 if (op == '*')
    21                     term *= n;
    22                 else
    23                     term /= n;
    24             }
    25         }
    26         return total;
    27     }
    28 };
  • 相关阅读:
    我該怎麼辦
    這麼多年興許從來沒有釋放過
    我想做一個快樂的孩子
    纠结
    如何克服心煩氣躁
    如何樹立威嚴
    第零次作业
    第三周作业
    第二周作业,
    第二周作业
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/8404430.html
Copyright © 2011-2022 走看看