一、题目 §
提取字符串中的最长合法简单数学表达式字符串长度最长的,并计算表达式的值。如果没有返回 0
简单数学表达式只能包含以下内容
0-9 数字,符号+-*
说明:
1.所有数字,计算结果都不超过 long
2.如果有多个长度一样的,请返回第一个表达式的结果
3.数学表达式,必须是最长的,合法的
4.操作符不能连续出现,如 +--+1 是不合法的
二、输入 §
字符串
三、输出 §
最长表达式值
四、示例 §
输入:
1-2abcd
输出:
-1
五、题解 §
- 理解题意后需要解决 2 个问题:
- 对于求“最长合法表达式”可以使用正则表达式匹配所有合法表达式。注意正则表达式需要使用
?:
非捕获组方式,否则匹配不到开始的操作数
- 对于计算表达式值,python 中直接使用
eval
函数;java 中需要自己实现,主要思想是操作数栈+操作符栈+运算符优先级,大学数据结构栈的经典应用题目
5.1 Java 实现 §
package org.stone.study.algo.ex202411;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 提取字符串中的最长合法简单数学表达式字符串长度最长的,并计算表达式的值。如果没有返回 0
* 简单数学表达式只能包含以下内容
* 0-9 数字,符号+-*
* 说明:
* 1.所有数字,计算结果都不超过 long
* 2.如果有多个长度一样的,请返回第一个表达式的结果
* 3.数学表达式,必须是最长的,合法的
* 4.操作符不能连续出现,如 +--+1 是不合法的
*/
public class MaxExprValue {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 1-2abcd
String str = scanner.nextLine();
long ans = maxExprValue(str);
// -1
System.out.println(ans);
}
public static long maxExprValue(String str) {
int ans = 0;
// 利用正则表达式找出所有合法的表达式
String regex = "\\d+(?:[-+*]\\d+)*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
String longestExpr = "";
int maxLen = 0;
while (matcher.find()) {
String expr = matcher.group();
if(expr.length() > maxLen) {
longestExpr = expr;
maxLen = expr.length();
}
}
if(longestExpr.isEmpty()) {
return 0;
}
// 求最长合法表达式的值
try {
return evaluateExpr(longestExpr);
} catch (Exception e) {
return 0;
}
}
// 计算表达式的值
private static long evaluateExpr(String expr) {
// 利用操作数栈和运算符栈对表达式求值
Stack<Long> numStack = new Stack<>();
Stack<Character> opStack = new Stack<>();
int n = expr.length();
long num = 0;
boolean hasNum = false;
for(int i = 0; i < n; i++) {
char c = expr.charAt(i);
// 处理操作数
if(Character.isDigit(c)) {
num = num * 10 + (c - '0');
hasNum = true;
} else { // 处理运算符
if(!hasNum) {
throw new RuntimeException("Invalid expression");
}
// 先将操作数入栈
numStack.push(num);
num = 0;
hasNum = false;
// 先计算高优先级的运算符,再将当前运算符入栈
while(!opStack.isEmpty() && priority(opStack.peek()) >= priority(c)) {
numStack.push(applyOp(numStack.pop(), numStack.pop(), opStack.pop()));
}
opStack.push(c);
}
}
// 处理最后一个操作数
if(hasNum) {
numStack.push(num);
}
// 处理剩余的运算符
while(!opStack.isEmpty()) {
numStack.push(applyOp(numStack.pop(), numStack.pop(), opStack.pop()));
}
return numStack.pop();
}
// 定义运算符的运算规则
private static long applyOp(long b, long a, char op) {
switch (op) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
default:
throw new RuntimeException("Invalid operator");
}
}
// 定义运算符的优先级
private static int priority(char op) {
switch (op) {
case '+':
case '-':
return 1;
case '*':
return 2;
default:
return 0;
}
}
}
5.2 Python实现 §
import re
def extract_and_calc(s):
# 正则表达式,匹配数字和运算符。注意要用非捕获组?:,否则不能匹配到开始的数字
matches = re.findall(r'\d+(?:[-+*]\d+)*', s)
if not matches:
return 0
# 找最长表达式
logest_match = max(matches, key=len)
try:
# 利用python的eval函数计算表达式
res = eval(logest_match)
return res
except:
return 0
if __name__ == '__main__':
s = input()
res = extract_and_calc(s)
print(res)