公式计算器
[题目链接](https://www.nowcoder.com/practice/b2ee481ca45c4c57b6ef5dfad1c86197)
思路
题目要求读入一个包含加、减、乘、幂四种运算的公式字符串,计算并输出结果。公式中可能出现 pow(a, b) 形式的幂运算。
Python / JavaScript:直接 eval
Python 内置 pow 函数,直接 eval(input()) 即可完成全部计算。
JavaScript 中没有全局 pow,但有 Math.pow,因此将输入中的 pow( 替换为 Math.pow( 后再 eval 即可。
C++ / Java:递归下降解析器
对于不支持安全 eval 的语言,需要手写表达式解析器。按照运算符优先级,定义如下文法:
expr -> term (('+' | '-') term)*
term -> factor ('*' factor)*
factor -> '-' factor | atom
atom -> NUMBER | 'pow' '(' expr ',' expr ')' | '(' expr ')'
expr处理加减,优先级最低。term处理乘法。factor处理一元负号。atom处理数字字面量、pow()函数调用和括号分组。
用一个全局指针 pos 扫描字符串,每个函数消费自己对应的语法结构并返回计算结果。
代码
[sol-Python3]
print(eval(input()))
[sol-C++]
#include <bits/stdc++.h>
using namespace std;
string s;
int pos;
void skipSpaces() {
while (pos < (int)s.size() && s[pos] == ' ') pos++;
}
long long parseExpr();
long long parseTerm();
long long parseFactor();
long long parseAtom();
long long parseExpr() {
long long val = parseTerm();
while (true) {
skipSpaces();
if (pos < (int)s.size() && s[pos] == '+') {
pos++; val += parseTerm();
} else if (pos < (int)s.size() && s[pos] == '-') {
pos++; val -= parseTerm();
} else break;
}
return val;
}
long long parseTerm() {
long long val = parseFactor();
while (true) {
skipSpaces();
if (pos < (int)s.size() && s[pos] == '*') {
pos++; val *= parseFactor();
} else break;
}
return val;
}
long long parseFactor() {
skipSpaces();
if (pos < (int)s.size() && s[pos] == '-') {
pos++;
return -parseFactor();
}
return parseAtom();
}
long long myPow(long long base, long long exp) {
if (exp < 0) return 0;
long long result = 1;
bool neg = false;
if (base < 0 && exp % 2 == 1) { neg = true; base = -base; }
else if (base < 0) { base = -base; }
for (long long i = 0; i < exp; i++) result *= base;
return neg ? -result : result;
}
long long parseAtom() {
skipSpaces();
if (pos + 2 < (int)s.size() && s.substr(pos, 3) == "pow") {
pos += 3;
skipSpaces();
pos++; // '('
long long a = parseExpr();
skipSpaces();
pos++; // ','
long long b = parseExpr();
skipSpaces();
pos++; // ')'
return myPow(a, b);
}
if (pos < (int)s.size() && s[pos] == '(') {
pos++;
long long val = parseExpr();
skipSpaces();
pos++; // ')'
return val;
}
long long val = 0;
bool neg = false;
if (pos < (int)s.size() && s[pos] == '-') { neg = true; pos++; }
while (pos < (int)s.size() && isdigit(s[pos])) {
val = val * 10 + (s[pos] - '0');
pos++;
}
return neg ? -val : val;
}
int main() {
getline(cin, s);
pos = 0;
cout << parseExpr() << endl;
return 0;
}
[sol-Java]
import java.util.Scanner;
public class Main {
static String s;
static int pos;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
s = sc.nextLine();
pos = 0;
System.out.println(parseExpr());
}
static void skipSpaces() {
while (pos < s.length() && s.charAt(pos) == ' ') pos++;
}
static long parseExpr() {
long val = parseTerm();
while (true) {
skipSpaces();
if (pos < s.length() && s.charAt(pos) == '+') {
pos++; val += parseTerm();
} else if (pos < s.length() && s.charAt(pos) == '-') {
pos++; val -= parseTerm();
} else break;
}
return val;
}
static long parseTerm() {
long val = parseFactor();
while (true) {
skipSpaces();
if (pos < s.length() && s.charAt(pos) == '*') {
pos++; val *= parseFactor();
} else break;
}
return val;
}
static long parseFactor() {
skipSpaces();
if (pos < s.length() && s.charAt(pos) == '-') {
pos++;
return -parseFactor();
}
return parseAtom();
}
static long myPow(long base, long exp) {
if (exp < 0) return 0;
long result = 1;
boolean neg = false;
if (base < 0 && exp % 2 == 1) { neg = true; base = -base; }
else if (base < 0) { base = -base; }
for (long i = 0; i < exp; i++) result *= base;
return neg ? -result : result;
}
static long parseAtom() {
skipSpaces();
if (pos + 2 < s.length() && s.substring(pos, pos + 3).equals("pow")) {
pos += 3;
skipSpaces();
pos++; // '('
long a = parseExpr();
skipSpaces();
pos++; // ','
long b = parseExpr();
skipSpaces();
pos++; // ')'
return myPow(a, b);
}
if (pos < s.length() && s.charAt(pos) == '(') {
pos++;
long val = parseExpr();
skipSpaces();
pos++; // ')'
return val;
}
long val = 0;
boolean neg = false;
if (pos < s.length() && s.charAt(pos) == '-') { neg = true; pos++; }
while (pos < s.length() && Character.isDigit(s.charAt(pos))) {
val = val * 10 + (s.charAt(pos) - '0');
pos++;
}
return neg ? -val : val;
}
}
[sol-JavaScript]
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
let s = line.replace(/pow\s*\(/g, 'Math.pow(');
console.log(eval(s));
rl.close();
});
复杂度分析
- 时间复杂度:
,其中
为输入字符串长度。递归下降解析器对字符串做一次线性扫描。
- 空间复杂度:
,其中
为表达式的嵌套深度(递归栈深度)。

京公网安备 11010502036488号