算法题: 包含MIN/MAX运算的四则运算

题目描述
输入4则运行算表达式, 额外再定义了两种运算操作
MIN(a,b) 计算最小值
MAX(a,b) 计算最大值
表达式不包括空格, 可以使用()设置优先级, 数字都是整数, 且输入一定合法, 不需要校验
例如 MIN(1,(2+3)*4)+(1+2)*3 的值为10

思路

  1. 遇到加减操作, 它之前的操作的优先级不会比现在低, 可以都消除掉.
    而当前的加减操作还不能消,先存到栈中
  2. 遇到乘除操作, 只能先消除掉它之前的乘除操作
  3. 遇到圆括号, 整个圆括号内的表达式最终可以消除1个值

js实现
打开 https://js.do/, 将以下代码复杂上去, 就可以直接运行了


// 用于字符串转整数
 const CharCode_0 = '0'.charCodeAt(0);
 const CharCode_9 = '9'.charCodeAt(0);

 // 扩展数组接口
 Array.prototype.peek = function () {
     return this[this.length-1];
 }

 const operations = {
     '+':  function(a, b) {
         return a + b;
     },
     '-':  function(a, b) {
        return a - b;
    },
    '*':  function(a, b) {
        return a * b;
    },
    '/':  function(a, b) {
        return Math.floor(a / b);
    },   
    'I':  function(a, b) { // MIN
        return Math.min(a, b);
    },
    'A':  function(a, b) { // MAX
        return Math.max(a, b);
    },   
 }

 // 简化字符遍历
class StringBuffer {
    constructor(str){
        this.str = str;
        this.pos = 0;
        this.len = str.length;
    }

    hasNext() {
        return this.pos < this.len;
    }

    peek() {
        return this.str.charAt(this.pos);
    }
    poll() {
        return this.str.charAt(this.pos++);
    }
    skip(n) {
        this.pos += n;
    }
    back(n) {
        this.pos -= n;
    }

    // 读取一个整数, 假设当前字节一定是个数字
    readNumber() {
        let n = 0;
        let c;
        while(this.pos < this.len) {
            c = this.str.charCodeAt(this.pos);
            if (c >= CharCode_0 && c <= CharCode_9) {
                n = n * 10 + (c - CharCode_0);
                this.pos++;
            }else{
                break;
            }
        }
        return n;
    }
}

// 计算表达式
function doEval(buf) {
    // 分别记录操作符和操作数
    const operatorStack = [];
    const operandStack = [];

    // 用于判断左括号之后, 直接出现正负符号
    let lastOpIsLeftParetness = false;  

    loop:
    while (buf.hasNext()) {
        const ch = buf.poll();
        let parentness = false;
        switch(ch) {
            case 'M': {
                // MIN, MAX操作
                const op = buf.poll(); // read I or A
                buf.skip(2); // skip N/X(
                
                // 第一个参数是遇到逗号结束
                const a = doEval(buf);
                // 第二个参数是遇到多出来的右括号结束
                const b = doEval(buf);    
                const r = operations[op](a, b);
                operandStack.push(r);
            }
            break;

            case '+':
            case '-':{
                if( operandStack.length === 0 || lastOpIsLeftParetness) {
                    // +/-表示符号
                    operandStack.push(0);
                }
                // 这之前的操作符可能的情况有
                // 1. 1个加减,跟随1个乘除, 从后往前消两次
                // 2. 1个加减操作, 消掉
                // 3. 1个乘除操作, 消掉
                // 不可能出现多个连续同级操作
                calc(operatorStack, operandStack);
                operatorStack.push(ch);
            }
            break;
 
            case '*':
            case '/':{
                // 这之前的操作符可能的情况有
                // 1. 1个加减,跟随之1个乘除, 只能消掉乘除操作
                // 2. 1个加减操作, 不能消
                // 3. 1个乘除操作, 消掉
                while (operatorStack.length > 0 ) {
                    const op = operatorStack.peek();
                    if (op === '*' || op === '/') {
                        operatorStack.pop();
                        const b = operandStack.pop();
                        const a = operandStack.pop();
                        const r = operations[op](a, b);
                        operandStack.push(r);                    
                    } else {
                        break;
                    }
                }  
                operatorStack.push(ch);              
            }
            break; 
            case '(': {
                operatorStack.push(ch);
                parentness = true;
            }  
            break;
            case ')': {
                if(!operatorStack.includes('(')) {
                    // 遇到右括号, 却没有左括号, 结束
                    break loop;
                }
                // 计算圆括号内的表达式
                while (operatorStack.length > 0 ) {
                    const op = operatorStack.pop();
                    if (op === '(') {
                        break;
                    }
                    const b = operandStack.pop();
                    const a = operandStack.pop();
                    const r = operations[op](a, b);
                    operandStack.push(r);
                }
            }  
            break;
            case ',': {
                // MIN/MAX的第一个参数结束标志
                break loop;
            }   
            default: {
                // 遇到数字
                buf.back(1);
                const num = buf.readNumber();
                operandStack.push(num);
            }   
        }
        lastOpIsLeftParetness = parentness;
    }
    calc(operatorStack, operandStack);
    return operandStack.pop();
}

function calc(operatorStack, operandStack) {
    while (operatorStack.length > 0 ) {
        const op = operatorStack.peek();
        if (op === '(') {
            break;
        }
        operatorStack.pop();
        const b = operandStack.pop();
        const a = operandStack.pop();
        // 注意a, b的先后顺序
        const r = operations[op](a, b);
        operandStack.push(r);
    }
}

function evaluate(express) {
    return doEval(new StringBuffer(express));
}

const thiz = this;
function main() {
    const expressions = [
        ['1+2+3+4', 10],
        ['1*2*3*4', 24],
        ['1+2+3+4+1*2*3*4', 34],
        ['1+(2+3+4+1*2*3*4+2+3+4+1)/3*4', 57],
        ['1+2*3', 7],
        ['1+(2)*3', 7],
        ['1+(-2)*3', -5],
        ['(1+(-2))*3', -3],
        ['(1+2)*3', 9],
        ['1+1/2*3', 1],
        ['1+3/2*3', 4],
        ['(1+(1+2)*3)/2', 5],
        ['MAX(1+2*3,(1+2)*3)', 9],
        ['MAX(MAX(1+2*3,(1+2)*3),1)', 9],
    ] 
    const output = [];
    for( const expr of expressions ) {
        const result = evaluate(expr[0]);
        output.push(`${expr[0]} = ${result}, expect: ${expr[1]}, ${result===expr[1]?'OK':'Error'}`);
    }
    console.log(output.join('\r\n'));

    // 浏览器上运行
    if(thiz.document) {
        thiz.document.write(output.join('
'
)); } } main();

你可能感兴趣的:(算法)