返回

秒杀笔试面试:手把手教会你表达式计算问题的万能解法

后端

双栈算法:征服表达式计算江湖的利器

在程序员的进阶之路上,表达式计算问题宛若一座巍峨高山,横亘在求职面试的关口。双栈算法,犹如一把屠龙之剑,将这道难题斩于马下。

双栈算法:化繁为简的秘诀

双栈算法遵循这样一个核心思想:将表达式的元素(操作数和运算符)依次压入两个栈中,通过依次处理这些元素来计算表达式的值。

算法原理:

  1. 将表达式的第一个元素压入操作数栈。
  2. 依次处理表达式的后续元素:
    • 如果是操作数,压入操作数栈。
    • 如果是运算符,从操作数栈弹出两个操作数,进行计算,将结果压入操作数栈。
  3. 重复步骤 2,直到表达式的所有元素都被处理完。
  4. 此 时,操作数栈顶的元素就是表达式的值。

算法步骤:

1. 创建两个栈:操作数栈和运算符栈。
2. 将表达式的第一个元素压入操作数栈。
3. 依次处理表达式的后续元素:
    * 如果是操作数,压入操作数栈。
    * 如果是运算符,从操作数栈弹出两个操作数,进行计算,将结果压入操作数栈。
4. 重复步骤 3,直到表达式的所有元素都被处理完。
5. 操作数栈顶的元素就是表达式的值。

代码实现:

def evaluate_expression(expression):
    """
    Evaluates the given expression using the double stack algorithm.

    Args:
        expression: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Create two stacks: operand stack and operator stack.
    operand_stack = []
    operator_stack = []

    # Tokenize the expression.
    tokens = expression.split()

    # Process the tokens one by one.
    for token in tokens:
        # If the token is an operand, push it to the operand stack.
        if token.isnumeric():
            operand_stack.append(int(token))

        # If the token is an operator, pop two operands from the stack, perform the
        # operation, and push the result back to the stack.
        else:
            operand2 = operand_stack.pop()
            operand1 = operand_stack.pop()
            result = perform_operation(token, operand1, operand2)
            operand_stack.append(result)

    # The value of the expression is the top element of the operand stack.
    return operand_stack[-1]


def perform_operation(operator, operand1, operand2):
    """
    Performs the given operation on the two given operands.

    Args:
        operator: The operator to perform.
        operand1: The first operand.
        operand2: The second operand.

    Returns:
        The result of the operation.
    """

    if operator == "+":
        return operand1 + operand2
    elif operator == "-":
        return operand1 - operand2
    elif operator == "*":
        return operand1 * operand2
    elif operator == "/":
        return operand1 / operand2
    else:
        raise ValueError("Invalid operator: {}".format(operator))

实战演练:用双栈算法秒杀 LeetCode

题目: 给定一个中缀表达式,计算其值。

示例:

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

思路:

  1. 将中缀表达式转换为后缀表达式(逆波兰表达式)。
  2. 利用双栈算法计算后缀表达式的值。

代码实现:

def evaluate_expression(expression):
    """
    Evaluates the given expression using the double stack algorithm.

    Args:
        expression: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Convert the expression to postfix notation.
    postfix_expression = infix_to_postfix(expression)

    # Evaluate the postfix expression using the double stack algorithm.
    return evaluate_postfix_expression(postfix_expression)


def infix_to_postfix(expression):
    """
    Converts the given infix expression to postfix notation.

    Args:
        expression: The infix expression to convert.

    Returns:
        The postfix notation of the expression.
    """

    # Create two stacks: operator stack and output stack.
    operator_stack = []
    output_stack = []

    # Tokenize the expression.
    tokens = expression.split()

    # Process the tokens one by one.
    for token in tokens:
        # If the token is an operand, push it to the output stack.
        if token.isnumeric():
            output_stack.append(token)

        # If the token is an operator, pop operators from the operator stack
        # until we find an operator with lower precedence. Push the popped
        # operators to the output stack. Then, push the current operator to
        # the operator stack.
        else:
            while operator_stack and precedence(token) <= precedence(operator_stack[-1]):
                output_stack.append(operator_stack.pop())
            operator_stack.append(token)

    # Pop all the remaining operators from the operator stack and push them
    # to the output stack.
    while operator_stack:
        output_stack.append(operator_stack.pop())

    # The postfix notation of the expression is the sequence of elements in
    # the output stack.
    return " ".join(output_stack)


def precedence(operator):
    """
    Returns the precedence of the given operator.

    Args:
        operator: The operator whose precedence is to be returned.

    Returns:
        The precedence of the operator.
    """

    if operator in "+-":
        return 1
    elif operator in "*/":
        return 2
    else:
        raise ValueError("Invalid operator: {}".format(operator))


def evaluate_postfix_expression(expression):
    """
    Evaluates the given postfix expression using the double stack algorithm.

    Args:
        expression: The postfix expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Create two stacks: operand stack and operator stack.
    operand_stack = []
    operator_stack = []

    # Tokenize the expression.
    tokens = expression.split()

    # Process the tokens one by one.
    for token in tokens:
        # If the token is an operand, push it to the operand stack.
        if token.isnumeric():
            operand_stack.append(int(token))

        # If the token is an operator, pop two operands from the stack, perform the
        # operation, and push the result back to the stack.
        else:
            operand2 = operand_stack.pop()
            operand1 = operand_stack.pop()
            result = perform_operation(token, operand1, operand2)
            operand_stack.append(result)

    # The value of the expression is the top element of the operand stack.
    return operand_stack[-1]


def perform_operation(operator, operand1, operand2):
    """
    Performs the given operation on the two given operands.

    Args:
        operator: The operator to perform.
        operand1: The first operand.
        operand2: The second operand.

    Returns:
        The result of the operation.
    """

    if operator == "+":
        return operand1 + operand2
    elif operator == "-":
        return operand1 - operand2
    elif operator == "*":
        return operand1 * operand2
    elif operator == "/":
        return operand1 / operand2
    else:
        raise ValueError("Invalid operator: {}".format(operator))

结语

双栈算法作为一种通用的表达式计算方法,具有高效、易于实现等优点,是解决表达式计算问题的利器。掌握了双栈算法,你将所向披靡,斩获求职面试中的表达式计算难题,开启程序员进阶的康庄大道。

常见问题解答

  1. 双栈算法的优点是什么?

    双栈算法具有高效、易于实现和通用性强的优点。它适用于各种表达式计算场景,如中缀、后缀和前缀表达式的计算。

  2. 双栈算法的不足之处是什么?

    双栈算法在面对复杂表达式时,可能会遇到运算符优先级和括号匹配等问题。需要额外处理机制来解决这些问题。

  3. 如何提高双栈算法的效率?

    可以采用优化数据结构、减少栈操作次数和预处理表达式等手段来提高双栈算法的效率。

  4. 双栈算法在实际应用中的场景有哪些?

    双栈算法广泛