Complicated Expression
2016 网易校招的一道题
写了一年多的lua, C++ 都生锈了,拿出来操练一下
在lisp语言中,表达式都用前缀法表示,例如,1 + 2 在lisp中使用(+ 1 2)来表示,其中,表达式的括号是必需的。Bob 想实现一种类 lisp 的脚本语言,这个语言中的表达式是这样定义的:
1、每个表达式的形式都是 ( operator arg_1 arg_2 ... ),即由左括号,运算符,运算数,和右括号组成。
2、运算符包括三种,分别是'+', '-', '*'。
3、运算符如果可以接受一个运算数,就称为一元运算符,如果可以接受两个运算数,就称为二元运算符,如果可以接受三个及以上运算数,就称为多元运算符。
+ 可以是一元,二元,乃至多元运算符。
(+ 9) 表示正整数9;
(+ 1 2) 代表 1 + 2;
(+ 1 2 3 4) 代表 1, 2, 3, 4 的连加和。
- 可以是一元或者二元运算符。
(- 9) 表示整数-9;
(- 5 4) 代表 5 - 4。
* 可以是二元运算符或者多元运算符。
(* 2 3) 代表 2 * 3;
(* 1 2 3 4) 代表 1 * 2 * 3 * 4。
4、运算数可以是一个正整数,或者0,还可以是另外一个表达式,例如
(+ (* 2, 3) 1) 也是一个合法的表达式,代表了 2 * 3 + 1
5、运算符与运算数之间,运算数与运算数相互之间都以空格进行分隔。在不产生歧义的情况下,空格也可以省略。例如,
(+ 2 3) 和 ( +2 3) 都被认为是合法的输入,且有相同的意义,代表 2 + 3。(+ 23)也是一个合法的输入,但其代表的是正整数23。
输入
输入由多行组成,第一行包含一个正整数T(T <= 5000)。代表共包含T组测试数据。
接下来会有T行输入。每一行包含一个表达式。这个表达式可能是一个合法的表达式,也可能是不合法的表达式。
每行数据所包含的字符数,不超过1000000。
输入数据中的数字全部是十进制正整数或者0,而且正整数的值不会大于65535。
输入中的表达式只包含三种不同类型的错误,除此之外的情况,都不必考虑。
第一类错误,括号不匹配,例如
(+ (* 2 3) 1)) 多了一个右括号;
+ 2 3 缺少括号等。
第二类错误,运算符缺失,例如
(2 3) 没有运算符。
第三类错误,运算符与数字不匹配,例如
(- 1 2 3),由于 - 只能接受最多两个算数,所以这也是一个不合法的表达式。
输出
对于合法的表达式,请输出表达式的值,对于不合法的表达式,请输出“invalid expression”。
可以假设最后的结果不超过32位整数的表示范围,但不保证在某些情况下,计算的中间值全部不超过32位整数的表示范围。
样例输入
5
(+ 1 (* 2 3)))
(2 3)
(- 3 2 1)
(+ (+ 1 2) (* 2 3) (- 2 1))
(- 2)
样例输出
invalid expression
invalid expression
invalid expression
10
-2
1、每个表达式的形式都是 ( operator arg_1 arg_2 ... ),即由左括号,运算符,运算数,和右括号组成。
2、运算符包括三种,分别是'+', '-', '*'。
3、运算符如果可以接受一个运算数,就称为一元运算符,如果可以接受两个运算数,就称为二元运算符,如果可以接受三个及以上运算数,就称为多元运算符。
+ 可以是一元,二元,乃至多元运算符。
(+ 9) 表示正整数9;
(+ 1 2) 代表 1 + 2;
(+ 1 2 3 4) 代表 1, 2, 3, 4 的连加和。
- 可以是一元或者二元运算符。
(- 9) 表示整数-9;
(- 5 4) 代表 5 - 4。
* 可以是二元运算符或者多元运算符。
(* 2 3) 代表 2 * 3;
(* 1 2 3 4) 代表 1 * 2 * 3 * 4。
4、运算数可以是一个正整数,或者0,还可以是另外一个表达式,例如
(+ (* 2, 3) 1) 也是一个合法的表达式,代表了 2 * 3 + 1
5、运算符与运算数之间,运算数与运算数相互之间都以空格进行分隔。在不产生歧义的情况下,空格也可以省略。例如,
(+ 2 3) 和 ( +2 3) 都被认为是合法的输入,且有相同的意义,代表 2 + 3。(+ 23)也是一个合法的输入,但其代表的是正整数23。
输入
输入由多行组成,第一行包含一个正整数T(T <= 5000)。代表共包含T组测试数据。
接下来会有T行输入。每一行包含一个表达式。这个表达式可能是一个合法的表达式,也可能是不合法的表达式。
每行数据所包含的字符数,不超过1000000。
输入数据中的数字全部是十进制正整数或者0,而且正整数的值不会大于65535。
输入中的表达式只包含三种不同类型的错误,除此之外的情况,都不必考虑。
第一类错误,括号不匹配,例如
(+ (* 2 3) 1)) 多了一个右括号;
+ 2 3 缺少括号等。
第二类错误,运算符缺失,例如
(2 3) 没有运算符。
第三类错误,运算符与数字不匹配,例如
(- 1 2 3),由于 - 只能接受最多两个算数,所以这也是一个不合法的表达式。
输出
对于合法的表达式,请输出表达式的值,对于不合法的表达式,请输出“invalid expression”。
可以假设最后的结果不超过32位整数的表示范围,但不保证在某些情况下,计算的中间值全部不超过32位整数的表示范围。
样例输入
5
(+ 1 (* 2 3)))
(2 3)
(- 3 2 1)
(+ (+ 1 2) (* 2 3) (- 2 1))
(- 2)
样例输出
invalid expression
invalid expression
invalid expression
10
-2
这题就是对栈的使用,学过数据结构的应该都会。只是时间长短而已,不得不承认工作久了写这种东西明显不如学生时代了。
源代码:
1 #include <iostream> 2 //#include <string> 3 #include <stack> 4 #include <stdio.h> 5 #include <string.h> 6 7 using namespace std; 8 9 typedef std::stack<std::string> strStack; 10 typedef std::stack<double> valueStack; 11 12 13 inline int parseStr(const char*& str, strStack &tempStack) 14 { 15 const char* begin = str; 16 const char* p = str; 17 while (*p) 18 { 19 char buf[50]; 20 if (*p == '(' || *p == '+' || *p == '-' || *p == '*') 21 { 22 buf[0] = *p; 23 buf[1] = 0; 24 tempStack.push(buf); 25 if (p == begin) 26 ++begin; 27 } 28 else if (*p == ' ') 29 { 30 if (p == begin) 31 ++begin; 32 else 33 { 34 int size = p - begin; 35 strncpy(buf, begin, size); 36 buf[size] = 0; 37 tempStack.push(buf); 38 begin = p + 1; 39 } 40 } 41 else if (*p == ')') 42 { 43 if (p != begin) 44 { 45 int size = p - begin; 46 strncpy(buf, begin, size); 47 buf[size] = 0; 48 tempStack.push(buf); 49 begin = p + 1; 50 } 51 ++p; 52 break; 53 } 54 else 55 { 56 // 可以做一些非法字符检查, 这题貌似不需要 57 } 58 ++p; 59 } 60 str = p; 61 return 0; 62 } 63 64 65 inline int calAdd(strStack& stack, double&result) 66 { 67 if (stack.size() < 1) 68 return -1; 69 70 double r = 0; 71 while (!stack.empty()) 72 { 73 std::string str = stack.top(); 74 stack.pop(); 75 double val; 76 sscanf(str.c_str(), "%lf", &val); 77 r += val; 78 } 79 result = r; 80 return 0; 81 } 82 83 inline int calSub(strStack& stack, double&result) 84 { 85 if (stack.size() < 1 || stack.size() > 2) 86 return -1; 87 88 std::string str = stack.top(); 89 stack.pop(); 90 double val1; 91 sscanf(str.c_str(), "%lf", &val1); 92 if (stack.size() == 0) 93 { 94 result = -val1; 95 return 0; 96 } 97 98 str = stack.top(); 99 stack.pop(); 100 double val2; 101 sscanf(str.c_str(), "%lf", &val2); 102 result = val1 - val2; 103 104 return 0; 105 } 106 107 inline int calMul(strStack& stack, double& result) 108 { 109 if (stack.size() < 1) 110 return -1; 111 112 double r = 1; 113 while ( !stack.empty()) 114 { 115 std::string str = stack.top(); 116 stack.pop(); 117 double val; 118 sscanf(str.c_str(), "%lf", &val); 119 r *= val; 120 } 121 result = r; 122 return 0; 123 } 124 125 126 // 成功返回0 127 int calSubOprator(strStack& stack, double &result) 128 { 129 int r = 0; 130 double val = 0; 131 std::string operaterStr = stack.top(); 132 stack.pop(); 133 if (operaterStr == "+") 134 { 135 r = calAdd(stack, val); 136 } 137 else if (operaterStr == "-") 138 { 139 r = calSub(stack, val); 140 } 141 else if (operaterStr == "*") 142 { 143 r = calMul(stack, val); 144 } 145 else 146 return -1; 147 148 if (r == -1) 149 return -1; 150 151 result = val; 152 return 0; 153 } 154 155 inline int calcStr(strStack &tempStack, valueStack& resultStack) 156 { 157 strStack temp; 158 while (true) 159 { 160 if (tempStack.empty()) 161 return -1; 162 163 std::string str = tempStack.top(); 164 if (str == "#") 165 { 166 double val = resultStack.top(); 167 resultStack.pop(); 168 tempStack.pop(); 169 char buf[50]; 170 sprintf(buf, "%d", int(val)); 171 temp.push(buf); 172 } 173 else if (str == "(") 174 { 175 tempStack.pop(); 176 break; 177 } 178 else 179 { 180 temp.push(tempStack.top()); 181 tempStack.pop(); 182 } 183 } 184 185 double val; 186 if (calSubOprator(temp, val) == -1) 187 return -1; 188 189 resultStack.push(val); 190 return 0; 191 } 192 193 194 int calc(const char* str, double &resultVal) 195 { 196 if (str == NULL || *str == 0) 197 return -1; 198 199 const char* p = str; 200 strStack tempStr; 201 valueStack tempVal; 202 203 while (true) 204 { 205 int r = 0; 206 r = parseStr(p, tempStr); 207 if (r == -1) 208 return -1; 209 210 r = calcStr(tempStr, tempVal); 211 if (r == -1) 212 return -1; 213 214 if (*p == 0) 215 { 216 if (tempStr.empty()) 217 { 218 resultVal = tempVal.top(); 219 tempVal.pop(); 220 } 221 else 222 return -1; 223 break; 224 } 225 else 226 { 227 // 临时结果入栈 228 tempStr.push("#"); 229 } 230 } 231 232 return 0; 233 } 234 235 236 int main() 237 { 238 239 const char*arr[] = { 240 "(+ 1 (* 2 3)))", 241 "(2 3)", 242 "(- 3 2 1)", 243 "(+ (+ 1 2) (* 2 3) (- 2 1))", 244 "(- 2)" 245 }; 246 247 248 for (int i = 0; i < 5; ++i) 249 { 250 const char* buf = arr[i]; 251 double result = 0; 252 if (calc(buf, result) == 0) 253 { 254 cout << result << endl; 255 } 256 else 257 { 258 cout << "invalid expression" << endl; 259 } 260 261 } 262 263 return 0; 264 }