Detailed Solution for Parsing Boolean Expressions on LeetCode

Saravana Sai Saravana Sai
7 min read

Understanding the Problem: Evaluating Boolean Expressions

In this problem, we are given a string representing a boolean expression, and we need to evaluate it to determine whether it's true or false. But what exactly is a boolean expression? Parsing Boolean Expression

What is a Boolean Expression?

A boolean expression is a statement that can be either true or false. Think of it like a question that can be answered with a simple "yes" or "no". For example, "Is it raining outside?" is a boolean expression because it can be either true (yes, it's raining) or false (no, it's not raining).

In this problem, we are dealing with a specific type of boolean expression that can be written in a certain format. Let's break it down.

The Format of the Boolean Expression

The boolean expression can be in one of the following shapes:

  • t (true)

  • f (false)

  • !(subExpr) (NOT subExpr)

  • &(subExpr1, subExpr2,..., subExprn) (AND of subExpr1, subExpr2,..., subExprn)

  • |(subExpr1, subExpr2,..., subExprn) (OR of subExpr1, subExpr2,..., subExprn)

Let's understand each of these shapes:

  • t and f are straightforward. They represent true and false values.

  • !(subExpr) means "NOT subExpr". For example, !(t) it means "NOT true", which is false.

  • &(subExpr1, subExpr2,..., subExprn) means "AND of subExpr1, subExpr2,..., subExprn". For example, &(t, f) it means "true AND false", which is false.

  • |(subExpr1, subExpr2,..., subExprn) means "OR of subExpr1, subExpr2,..., subExprn". For example, |(f, t) it means "false OR true", which is true.

Evaluating the Boolean Expression

Our task is to evaluate the given boolean expression and determine whether it's true or false. We can do this by following the order of operations:

  1. Evaluate the innermost expressions first (i.e., the subExprs inside the parentheses).

  2. Apply the logical operations (NOT, AND, OR) to the evaluated expressions.

  3. Repeat steps 1 and 2 until we have a final true or false value.

Intuition

When tackling the problem of evaluating a boolean expression with nested parentheses, our initial thought is to identify and evaluate the innermost expressions first. This is because the values of the inner expressions will be used to determine the values of the outer expressions.

To achieve this, we can utilize a stack data structure to keep track of the expressions and their evaluations. The idea is to push the characters of the expression onto the stack, and when we encounter a closing parenthesis ), we know that we have reached the end of an inner expression.

Common Data Structures for Programmers

Class Structure

The class has a single instance variable $stack of type SplStack, which is a PHP class that implements a stack data structure. The class also has several methods:

  • __construct: Initializes the $stack instance variable with a new SplStack object.

  • evalWithOp: Evaluates a list of values with a given operator (& or |).

  • parseInnerExp: Parses an inner expression (i.e., a sub-expression enclosed in parentheses) and evaluates it using evalWithOp.

  • evalExp: Evaluates a single expression (i.e., a sub-expression enclosed in parentheses) and returns a boolean value.

  • getExpression: Retrieves an inner expression from the stack by popping elements until a ( is found.

  • parseBoolExpr: The main method that parses and evaluates the input boolean expression.

Method Explanations

evalWithOp

This method takes an array of values and an operator (& or |) as input. It creates a new stack opStack and pushes all values onto it. Then, it enters a loop that continues until opStack it is empty. In each iteration, it:

  1. Checks if opStack has only one element left. If so, it returns the value of that element ("t" or "f").

  2. Pops two elements from opStack, converts them to boolean values (true or false), and applies the given operator (& or |) to them.

  3. Pushes the result of the operation back onto opStack.

public function evalWithOp(array $values, string $op): bool
    {
        $opStack = new SplStack();
        foreach ($values as $value) {
            $opStack->push($value);
        }

        if ($opStack->count() == 1) {
            return $opStack->pop() == "t" ? true : false;
        }

        while (!$opStack->isEmpty()) {

            if ($opStack->count() == 1) {
                return $opStack->pop() == "t" ? true : false;
            }

            $opOne = $opStack->pop();
            $opTwo = $opStack->pop();
            $leftOp = $opOne == "t" ? true : false;
            $rightOp = $opTwo == "t" ? true : false;

            if ($op == "&") {
                $opStack->push(($leftOp && $rightOp) ? "t" : "f");
            }

            if ($op == "|") {
                $opStack->push(($leftOp || $rightOp) ? "t" : "f");
            }
        }
    }

parseInnerExp

This method takes an inner expression (a string) and an operator (& or |) as input. It:

  1. Splits the inner expression into an array of values using commas as separators.

  2. Calls evalWithOp to evaluate the array of values with the given operator.

  3. Returns the result of the evaluation.

evalExp

This method takes a single expression (a string) as input. It:

  1. Checks the first character of the expression:

    • If it's &, calls parseInnerExp with the inner expression (everything except the first and last characters) and the & operator.

    • If it's |, calls parseInnerExp with the inner expression and the | operator.

    • If it's !, calls parseInnerExp with the inner expression and the ! operator, and negates the result.

  2. Returns the result of the evaluation.

getExpression

This method retrieves an inner expression from the stack by popping elements until a ( is found. It:

  1. Initializes an empty string innerExp.

  2. While the top element of the stack is not (, pops the top element and prepends it to innerExp.

  3. Pops the ( element and prepends it to innerExp.

  4. Returns the complete inner expression.

 public function getExpression(): string
    {
        $innerExp = "";
        while ($this->stack->top() != "(") {
            $innerExp = $this->stack->pop() . $innerExp;
        }
        $innerExp = $this->stack->pop() . $innerExp;
        return  $this->stack->pop() . $innerExp;
    }

parseBoolExpr

This method is the main entry point for parsing and evaluating a boolean expression. It:

  1. Iterates over the input expression character by character.

  2. When a ) is encountered, it:

    • Calls getExpression to retrieve the inner expression.

    • Calls evalExp to evaluate the inner expression.

    • Pushes the result of the evaluation onto the stack.

  3. When a non-) character is encountered, it simply pushes the character onto the stack.

  4. After iterating over the entire expression, returns the top element of the stack ("t" or "f").

public function parseBoolExpr(string $exp): bool
    {
        $expLen = strlen($exp);
        for ($i = 0; $i < $expLen; $i++) {
            if ($exp[$i] == ")") {
                $this->stack->push($exp[$i]);
                $innerExp = $this->getExpression();
                $expValue = $this->evalExp($innerExp);
                $this->stack->push($expValue ? "t" : "f");
                continue;
            } else {
                $this->stack->push($exp[$i]);
                continue;
            }
        }
        return $this->stack->top()=="t" ? true : false;
    }

Final Code

class Solution
{
    public SplStack $stack;

    public function __construct()
    {
        $this->stack = new SplStack();
    }

    public function evalWithOp(array $values, string $op): bool
    {
        $opStack = new SplStack();
        foreach ($values as $value) {
            $opStack->push($value);
        }

        if ($opStack->count() == 1) {
            return $opStack->pop() == "t" ? true : false;
        }

        while (!$opStack->isEmpty()) {

            if ($opStack->count() == 1) {
                return $opStack->pop() == "t" ? true : false;
            }

            $opOne = $opStack->pop();
            $opTwo = $opStack->pop();
            $leftOp = $opOne == "t" ? true : false;
            $rightOp = $opTwo == "t" ? true : false;

            if ($op == "&") {
                $opStack->push(($leftOp && $rightOp) ? "t" : "f");
            }

            if ($op == "|") {
                $opStack->push(($leftOp || $rightOp) ? "t" : "f");
            }
        }
    }

    public function parseInnerExp(string $exp, string $op)
    {
        $values = explode(",", $exp);
        return $this->evalWithOp($values, $op);
    }

    public function evalExp(string $innerExp): bool
    {
        if ($innerExp[0] == "&") {
            return $this->parseInnerExp(substr($innerExp, 2, -1), "&");
        }

        if ($innerExp[0] == "|") {
            return $this->parseInnerExp(substr($innerExp, 2, -1), "|");
        }

        if ($innerExp[0] == "!") {
            return !$this->parseInnerExp(substr($innerExp, 2, -1), "!");
        }
        return true;
    }


    public function getExpression(): string
    {
        $innerExp = "";
        while ($this->stack->top() != "(") {
            $innerExp = $this->stack->pop() . $innerExp;
        }
        $innerExp = $this->stack->pop() . $innerExp;
        return  $this->stack->pop() . $innerExp;
    }
    /**
     * @param String $exp
     * @return Boolean
     */
    public function parseBoolExpr(string $exp): bool
    {
        $expLen = strlen($exp);
        for ($i = 0; $i < $expLen; $i++) {
            if ($exp[$i] == ")") {
                $this->stack->push($exp[$i]);
                $innerExp = $this->getExpression();
                $expValue = $this->evalExp($innerExp);
                $this->stack->push($expValue ? "t" : "f");
                continue;
            } else {
                $this->stack->push($exp[$i]);
                continue;
            }
        }
        return $this->stack->top()=="t" ? true : false;
    }
}

Conclusion

we explored the problem of evaluating a boolean expression with nested parentheses and presented a solution that utilizes a stack data structure to efficiently evaluate the expressions. By breaking down the problem into smaller sub-problems and using a stack to track the expressions and their evaluations, we can correctly determine the final result of the boolean expression.

Have you encountered similar problems involving nested structures? How did you approach them? Share your experiences and insights in the comments below!

What do you think about this solution? Do you have any suggestions or improvements? Let us know in the comments below!

0
Subscribe to my newsletter

Read articles from Saravana Sai directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Saravana Sai
Saravana Sai

I am a self-taught web developer interested in building something that makes people's life awesome. Writing code for humans not for dump machine