csp认证java答案 csp java_csp认证java答案

csp认证java答案 csp java_csp认证java答案_02

代码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;
    }
}