Force buckle 227-227. Basic calculator II

Time:2021-9-24

This problem is similar to the general computational solution, which can be solved by stack. When optimizing, we can take advantage of the particularity of the problem itself.

Original title

Implement a basic calculator to calculate the value of a simple string expression.

String expressions contain only non negative integers, +, -, *, / operators and spaces   。 Integer division preserves only the integer part.

Example   1:

Input: "3 + 2 * 2"
Output: 7

Example 2:

Input: "3 / 2"
Output: 1

Example 3:

Input: "3 + 5 / 2"
Output: 5

explain:

  • You can assume that the given expressions are valid.
  • Do not use the built-in library function eval.

Original title URL: https://leetcode-cn.com/probl…

answer

Stack

The first thing I think of in this problem is to use two stacks to store operators and numbers. When traversing, first put the corresponding characters on the stack. When encountering high-level operations (for example, / is higher than +, -), directly put them on the stack, otherwise press out the number for calculation.

Let’s look at the code:

class Solution {
    public int calculate(String s) {
        //Symbol stack
        Stack<Character> signStack = new Stack<>();
        //Digital stack
        Stack<Integer> numStack = new Stack<>();
        //Used to store the level of the operator
        Map<Character, Integer> signLevelMap = new HashMap<>(6);
        //+, - are low-level operators
        signLevelMap.put('+', 1);
        signLevelMap.put('-', 1);
        //*, / are high-level operators
        signLevelMap.put('*', 2);
        signLevelMap.put('/', 2);

        //Traversal
        int tempNum = 0;
        for (char charS : s.toCharArray()) {
            //Skip spaces
            if (charS == ' ') {
                continue;
            }

            Integer level = signLevelMap.get(charS);
            //If the current is a number
            if (level == null) {
                tempNum = charS - '0' + tempNum * 10;
                continue;
            }

            //If the current is a symbol, press the previous number into numstack
            numStack.push(tempNum);
            tempNum = 0;

            //If there is no previous symbol, the current symbol is directly pushed onto the stack
            if (signStack.empty()) {
                signStack.push(charS);
                continue;
            }

            //If there is a symbol before, look at the two levels
            Character signBefore = signStack.peek();
            int levelBefore = signLevelMap.get(signBefore);
            //If current level > previous level
            if (level > levelBefore) {
                //Pushes the current symbol directly onto the stack
                signStack.push(charS);
                continue;
            }

            //If the current level < = the previous level, the previous symbol can be calculated directly
            while (level <= levelBefore) {
                signStack.pop();
                int num2 = numStack.pop();
                int num1 = numStack.pop();
                int result = 0;
                switch (signBefore) {
                    case '+':
                        result = num1 + num2;
                        break;
                    case '-':
                        result = num1 - num2;
                        break;
                    case '*':
                        result = num1 * num2;
                        break;
                    case '/':
                        result = num1 / num2;
                        break;
                }
                //Push the result into the stack again
                numStack.push(result);

                if (signStack.empty()) {
                    break;
                }
                signBefore = signStack.peek();
                levelBefore = signLevelMap.get(signBefore);
            }
            //Press the symbol into the signstack
            signStack.push(charS);
        }
        //Press the last number into numstack
        numStack.push(tempNum);

        //Calculate all data in the stack
        int result = 0;
        while (!signStack.empty()) {
            char sign = signStack.pop();
            int num2 = numStack.pop();
            int num1 = numStack.pop();
            switch (sign) {
                case '+':
                    result = num1 + num2;
                    break;
                case '-':
                    result = num1 - num2;
                    break;
                case '*':
                    result = num1 * num2;
                    break;
                case '/':
                    result = num1 / num2;
                    break;
            }
            //Push the result into the stack again
            numStack.push(result);
        }
        return numStack.pop();
    }
}

The submission was successful, but the execution time was only defeated43.97%Java submission records can certainly be optimized.

Combined with topic characteristics

The reason why the above is slow should be related to pressing the stack and entering the stack, because it is equivalent to repeatedly calculating and re traversing the content that has been traversed. Is there any way to directly traverse and end at one time?

The title says only+、-、*、/Four operators, if yes+、-, cannot be evaluated directly because the next operator may be*、\, those with higher grades will be given priority. But if so*、/, it can be calculated directly, because there is no higher level than them.

So how to solve it+、-What about the direct calculation? Actually, we can+、-The following expressions are treated as a whole until they are encountered again+、-。 For this whole, there are two situations:

  1. Just a number
  2. from*、/In this case, the result can be calculated directly, which is also a number.

In this way, we can ensure that we can directly calculate the answer by traversing it once. Next, look at the code:

class Solution {
    public int calculate(String s) {
        //Find the first number first
        int[] resultArray = findNum(0, s);
        int result = resultArray[0];
        //Start traversal
        for (int i = resultArray[1] + 1; i < s.length(); i++) {
            char charS = s.charAt(i);
            //Skip spaces
            if (charS == ' ') {
                continue;
            }
            //*, / calculated directly
            if (charS == '*' || charS == '/') {
                resultArray = findNum(i + 1, s);
                i = resultArray[1];
                result = (charS == '*') ? (result * resultArray[0]) : (result / resultArray[0]);
                continue;
            }
            //+, - take it as a whole and calculate it again
            if (charS == '+' || charS == '-') {
                resultArray = findWholeNum(i + 1, s);
                i = resultArray[1];
                result = (charS == '+') ? (result + resultArray[0]) : (result - resultArray[0]);
            }
        }
        return result;
    }

    /**
     *Treat the following expression as a whole.
     *Returns an array. The subscript 0 represents the result of the expression, and the subscript 1 represents the subscript at the end of the expression.
     */
    public int[] findWholeNum(int index, String s) {
        //First number found
        int[] resultArray = findNum(index, s);
        int result = resultArray[0];
        int newIndex = resultArray[1] + 1;
        for (; newIndex < s.length(); newIndex++) {
            char charS = s.charAt(newIndex);
            if (charS == ' ') {
                continue;
            }
            //It ends when you encounter +, -
            if (charS == '+' || charS == '-') {
                break;
            }

            if (charS == '*' || charS == '/') {
                resultArray = findNum(newIndex + 1, s);
                newIndex = resultArray[1];
                result = (charS == '*') ? (result * resultArray[0]) : (result / resultArray[0]);
            }
        }
        resultArray = new int[]{result, newIndex - 1};
        return resultArray;
    }

    /**
     *Find the next number.
     *Returns an array. The subscript 0 represents the value of a number, and the subscript 1 represents the subscript at the end of a number.
     */
    public int[] findNum(int index, String s) {
        int num = 0;
        int newIndex = index;
        for (; newIndex < s.length(); newIndex++) {
            char charS = s.charAt(newIndex);
            if (charS == ' ') {
                continue;
            }

            if (charS > '9' || charS < '0') {
                break;
            }

            num = charS - '0' + num * 10;
        }
        return new int[]{num, newIndex - 1};
    }
}

Submit OK and the execution time is over96.66%Java submission records, which should also be OK.

summary

The above is my answer to this question. I don’t know if you understand it. This problem can be solved by stack or more efficiently by taking advantage of the particularity of the problem itself.

If you are interested, you can visit my blog or follow my public number and headline number. There may be an unexpected surprise.

https://death00.github.io/

Public account: Jiancheng Road

Force buckle 227-227. Basic calculator II

Force buckle 227-227. Basic calculator II

Recommended Today

NPM & node upgrade latest version

Version view $ npm -v npm WARN npm npm does not support Node.js v14.8.0 npm WARN npm You should probably upgrade to a newer version of node as we npm WARN npm can’t make any promises that npm will work with this version. npm WARN npm You can find the latest version at https://nodejs.org/ 8.0.0 […]