代码1(100分)
一般计算表达式都是用栈这个数据结构,两个栈,一个存数字,一个存运算符。
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args){
Stack<Integer> numStack = new Stack<>(); // 数字栈
Stack<Character> operStack = new Stack<>(); // 符号栈
int res, ans, index; // res是表达式最终的值,ans是临时计算的值,index是扫描表达式的索引
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String[] s = new String[n];
for(int i = 0; i < n; i++){
s[i] = in.next();
}
in.close();
for(int i = 0; i < n; i++){
// 初始化
res = ans = index = 0; // 初始化为零
while(!numStack.isEmpty()){ // 初始化数字栈为空栈
numStack.pop();
}
while(!operStack.isEmpty()){ // 初始化符号栈为空栈
operStack.pop();
}
// 扫描表达式,处理减、乘、除法
while(index < s[i].length()){ // 开始扫描表达式
if(s[i].charAt(index) <= '9' && s[i].charAt(index) >= '0'){ // 如果是数字,入数字栈
numStack.push(Integer.parseInt(s[i].substring(index, index+1)));
}else if(s[i].charAt(index) == '+'){ // 如果是加号,入符号栈
operStack.push(s[i].charAt(index));
}else if(s[i].charAt(index) == '-'){ // 如果是减号,改成加号入符号栈。同时,让下一个数字(正数)变成相反数(负数)
operStack.push('+');
numStack.push((Integer.parseInt(s[i].substring(index+1, index+2))) * (-1));
index++; // 由于已经处理运算符之后的数字,所以index要自增一次
}else if(s[i].charAt(index) == 'x'){ // 如果是乘号,不入符号栈。而是从数字栈取出栈顶的数字,与乘号的下一个数字做乘法运算,并将结果入数字栈
ans = numStack.pop();
numStack.push(ans * (Integer.parseInt(s[i].substring(index+1, index+2))));
index++; // 由于已经处理运算符之后的数字,所以index要自增一次
}else { // 如果是除号,不入符号栈。而是从数字栈取出栈顶的数字,与除号的下一个数字做除法运算,并将结果入数字栈
ans = numStack.pop();
numStack.push(ans / (Integer.parseInt(s[i].substring(index+1, index+2))));
index++; // 由于已经处理运算符之后的数字,所以index要自增一次
}
index++;
}
// 计算最终值
while(!numStack.isEmpty()){ // 将数字栈里面的数字直接相加,得到的结果就是表达式的值
res += numStack.pop();
}
// 判断
if(res == 24){
System.out.println("Yes");
}else{
System.out.println("No");
}
}
}
}
代码2(100分)
使用BufferedReader类进行输入,在时间和内存的耗费上都要比Scanner类要好。在输入方面,BufferedReader类比Scanner类的效率要高,只是能用的方法相对来说要少一点。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws IOException{
Stack<Integer> numStack = new Stack<>(); // 数字栈
Stack<Character> operStack = new Stack<>(); // 符号栈
int res, num, index;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
int n = Integer.parseInt(s);
for(int i = 0; i < n; i++){
// 初始化
res = num = index = 0; // 清零
while(!numStack.isEmpty()){ // 清空数字栈
numStack.pop();
}
while(!operStack.isEmpty()){ // 清空符号栈
operStack.pop();
}
// 扫描表达式,处理乘、除法
s = br.readLine();
while(index < s.length()){
if(s.charAt(index) >= '0' && s.charAt(index) <= '9'){ // 如果是数字,就入数字栈
numStack.push(Integer.parseInt(s.substring(index, index+1)));
}else if(s.charAt(index) == '+'){ // 如果是加号,就入符号栈
operStack.push(s.charAt(index));
}else if(s.charAt(index) == '-'){ // 如果是减号,变成加号入符号栈,然后让减号之后的数字变成相反数入数字栈
operStack.push('+');
numStack.push(Integer.parseInt(s.substring(index+1, index+2)) * (-1));
index++;
}else if(s.charAt(index) == 'x'){ // 如果是乘号,则取数字栈顶数字与乘号之后的数字做乘法运算后,将其结果入数字栈
num = numStack.pop();
numStack.push(num * Integer.parseInt(s.substring(index+1, index+2)));
index++;
}else{ // 如果是除号,则取数字栈顶数字与除号之后的数字做除法运算后,将其结果入数字栈
num = numStack.pop();
numStack.push(num / Integer.parseInt(s.substring(index+1, index+2)));
index++;
}
index++;
}
// 统计结果
while(!numStack.isEmpty()){
res += numStack.pop();
}
// 判断
if(res == 24){
System.out.println("Yes");
}else{
System.out.println("No");
}
}
br.close();
}
}
代码3(30分)
代码3与代码1的不同之处,在于对减号的处理,以及最后的计算。提交后只有30分,希望有大佬能指出错误之处。
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Stack<Integer> numStack = new Stack<>(); // 数字栈
Stack<Character> operStack = new Stack<>(); // 符号栈
int sum, index; // sum存储临时计算的值,index是扫描表达式的索引
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String[] s = new String[n];
for(int i = 0; i < n; i++) {
s[i] = in.next();
}
in.close();
for(int i = 0; i < n; i++) {
// 初始化变量和栈
sum = index = 0;
while(!numStack.isEmpty()) {
numStack.pop();
}
while(!operStack.isEmpty()) {
operStack.pop();
}
// 扫描表达式
while(index < s[i].length()) {
if(s[i].charAt(index) >= '0' && s[i].charAt(index) <= '9') { // 如果是数字,直接入数字栈
numStack.push(Integer.parseInt(s[i].substring(index, index + 1)));
}else if(s[i].charAt(index) == '+' || s[i].charAt(index) == '-') { // 如果是加号或减号,入符号栈
operStack.push(s[i].charAt(index));
}else if(s[i].charAt(index) == 'x') { // 如果是乘号,从数字栈出栈一个数字,与乘号之后的数字相乘,其结果入数字栈
sum = numStack.pop();
numStack.push(sum * (Integer.parseInt(s[i].substring(index+1, index+2))));
index++; // 由于已经扫描了符号后面的数字,所以要跳过
}else { // 如果是除号,从数字栈出栈一个数字,与除号之后的数字相除,其结果入数字栈
sum = numStack.pop();
numStack.push(sum / (Integer.parseInt(s[i].substring(index+1, index+2))));
index++; // 由于已经扫描了符号后面的数字,所以要跳过
}
index++;
}
// 计算最终值
while(!operStack.isEmpty()) {
sum = numStack.pop();
if(operStack.pop() == '-') {
numStack.push(numStack.pop() - sum);
}else {
numStack.push(sum + numStack.pop());
}
}
// 判断
if(numStack.pop() == 24) {
System.out.println("Yes");
}else {
System.out.println("No");
}
}
}
}
代码4(60分)
为了方便计算,自己设计了一个类似于栈的数据结构,但是只有60分,希望有大佬指出错误之处。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String[] s = new String[n];
for(int i = 0; i < n; i++){
s[i] = in.next();
}
in.close();
for(int i = 0; i < n; i++){
MyStack numStack = new MyStack(4); // 数字栈,存放数字
MyStack operStack = new MyStack(3); // 符号栈,存放符号
int index = 0; // 扫描索引
int num1, num2, res, oper; // 临时计算用
char ch; // 用于保存每次扫描的字符,当前运算符
// 扫描表达式,并处理乘除运算
while(true){
// 先扫描字符
ch = s[i].charAt(index); // 扫描字符
// 再判断字符是数字还是运算符,再做相应处理
if(operStack.isOper(ch)){ // 如果当前符号是运算符
// 判断当前符号栈是否为空
// 如果符号栈非空,则比较当前符号与栈顶符号。如果当前运算符优先级小于等于栈顶运算符,则需要从数栈中pop出
// 两个数,再从符号栈中pop出一个运算符,进行计算,并将计算结果入数栈,再将当前运算符入符号栈
if(!operStack.isEmpty()){ // 如果符号栈非空
if(operStack.priority(ch) <= operStack.priority(operStack.peek())){ // 当前运算符优先级小于等于栈顶运算符
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
numStack.push(res); // 计算结果入数栈
operStack.push(ch); // 将当前符号入符号栈
}else{ // 如果当前运算符优先级大于栈顶优先级
operStack.push(ch); // 直接入栈
}
}else{ // 如果符号栈为空
operStack.push(ch); // 直接将符号入栈
}
}else{ // 如果是数字,则直接入数字栈
numStack.push(Integer.parseInt(s[i].substring(index, index + 1))); // 本题不用考虑多位数
}
// 判断是否扫描到表达式最后
index++;
if(index >= s[i].length()){
break;
}
}// 表达式扫描完毕
// 顺序从数栈和符号栈中pop出相应的数和运算符计算
while(true){
// 如果符号栈为空,说明计算到最后的结果,数栈中只有一个数字,就是最终结果
if(operStack.isEmpty()){
break;
}
// 符号栈非空
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
numStack.push(res); // 计算结果入栈
}
// 此时数栈中栈顶数就是结果
if(numStack.pop() == 24){
System.out.println("Yes");
}else{
System.out.println("No");
}
}
}
}
class MyStack{
private int maxSize; // 栈的大小
private int[] stack; // 底层用数组模拟栈
private int top = -1; // 栈顶指针,初始化为-1
// 构造器
public MyStack(int maxSize){
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
// 返回当前栈顶的值peek,但不删除栈顶值
public int peek(){
return stack[top];
}
// 判断栈是否已满
public boolean isFull(){
return top == maxSize - 1;
}
// 判断栈是否为空
public boolean isEmpty(){
return top == -1;
}
// 入栈push
public void push(int value){
// 先判断是否栈满
if(this.isFull()){
System.out.println("栈已满,无法完成入栈操作!");
return; // 结束方法
}
// 栈没有满
top++;
stack[top] = value;
}
// 出栈pop,返回且删除栈中栈顶的值
public int pop(){
// 先判断是否栈空
if(this.isEmpty()){
// 抛出异常
throw new RuntimeException("栈空,无法完成出栈操作!");
}
// 栈非空
int value = stack[top];
top--;
return value;
}
// 显示栈中的内容,既遍历栈,遍历时从栈顶开始
public void list(){
// 先判断是否栈空
if(this.isEmpty()){
System.out.println("栈空,没有数据!");
return; // 结束方法
}
// 栈非空
for(int i = top; i > -1; i--){
System.out.print(stack[i] + " ");
}
}
// 判断是否是一个运算符
public boolean isOper(char val){
return val == 'x' || val == '/' || val == '+' || val == '-'; // 根据题目要求,乘号是小写的字母x
}
// 返回运算符的优先级,返回的数字越大,优先级越高
public int priority(int oper){
if(oper == 'x' || oper == '/'){ // 根据题目要求,乘号是小写的字母x
return 1;
}else if(oper == '+' || oper == '-'){
return 0;
}else{
return -1;
}
}
// 计算
public int cal(int num1, int num2, int oper){
int res = 0; // 存放计算结果
switch(oper){
case '+' :
res = num1 + num2;
break;
case '-' :
res = num2 - num1; // 注意顺序,因为栈是先进后出
break;
case 'x' : // 根据题目要求,乘号是小写的字母x
res = num1 * num2;
break;
case '/' :
res = num1 / num2;
break;
default :
break;
}
return res;
}
}