Java - Boolean Parenthesization Problem

Problem Statement

Given a Boolean expression S containing T (true), F (false), & (AND), | (OR), ^ (XOR),

Find the number of ways to parenthesize S so that the result is True.

Example 1

Input: S = "T|F&T^T"

Output: 4

Explanation:

- (T | (F & (T ^ T))) → True

- ((T | F) & (T ^ T)) → True

- (T | (F & T)) ^ T → True

- ((T | (F & T)) ^ T) → True

Approach 1: Recursive Solution

We recursively evaluate all possible parenthesizations.

public class BooleanParenthesization {

    public static int countWays(String s, int i, int j, boolean isTrue) {

        if (i > j) return 0; // Invalid case

        if (i == j) { // Base case: single character

            if (isTrue) return s.charAt(i) == 'T' ? 1 : 0;

            else return s.charAt(i) == 'F' ? 1 : 0;

        }

        int ways = 0;

        for (int k = i + 1; k < j; k += 2) { // Operators at odd positions

            int leftTrue = countWays(s, i, k - 1, true);

            int leftFalse = countWays(s, i, k - 1, false);

            int rightTrue = countWays(s, k + 1, j, true);

            int rightFalse = countWays(s, k + 1, j, false);

            char operator = s.charAt(k);

            if (operator == '&') {

                if (isTrue) ways += leftTrue * rightTrue;

                else ways += leftFalse * rightTrue + leftTrue * rightFalse + leftFalse * rightFalse;

            } else if (operator == '|') {

                if (isTrue) ways += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;

                else ways += leftFalse * rightFalse;

            } else if (operator == '^') {

                if (isTrue) ways += leftTrue * rightFalse + leftFalse * rightTrue;

                else ways += leftTrue * rightTrue + leftFalse * rightFalse;

            }

        }

        return ways;

    }

    public static void main(String[] args) {

        String s = "T|F&T^T";

        int n = s.length();

        System.out.println("Ways to parenthesize for True: " + countWays(s, 0, n - 1, true)); // Output: 4

    }

}

Complexity Analysis

Time Complexity: O(2^N) (Exponential)

Space Complexity: O(N) (Recursive Stack)

Approach 2: Memoization (Top-Down DP)

To avoid redundant calculations, we use a HashMap (dp).

import java.util.*;

public class BooleanParenthesizationMemo {

    static Map<String, Integer> dp = new HashMap<>();

    public static int countWays(String s, int i, int j, boolean isTrue) {

        if (i > j) return 0;

        if (i == j) return (isTrue == (s.charAt(i) == 'T')) ? 1 : 0;

        String key = i + "_" + j + "_" + isTrue;

        if (dp.containsKey(key)) return dp.get(key);

        int ways = 0;

        for (int k = i + 1; k < j; k += 2) {

            int leftTrue = countWays(s, i, k - 1, true);

            int leftFalse = countWays(s, i, k - 1, false);

            int rightTrue = countWays(s, k + 1, j, true);

            int rightFalse = countWays(s, k + 1, j, false);

            char operator = s.charAt(k);

            if (operator == '&') {

                if (isTrue) ways += leftTrue * rightTrue;

                else ways += leftFalse * rightTrue + leftTrue * rightFalse + leftFalse * rightFalse;

            } else if (operator == '|') {

                if (isTrue) ways += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;

                else ways += leftFalse * rightFalse;

            } else if (operator == '^') {

                if (isTrue) ways += leftTrue * rightFalse + leftFalse * rightTrue;

                else ways += leftTrue * rightTrue + leftFalse * rightFalse;

            }

        }

        dp.put(key, ways);

        return ways;

    }

    public static void main(String[] args) {

        String s = "T|F&T^T";

        int n = s.length();

        System.out.println("Ways to parenthesize for True: " + countWays(s, 0, n - 1, true)); // Output: 4

    }

}

Complexity Analysis

Time Complexity: O(N^3)

Space Complexity: O(N^2)

Approach 3: Bottom-Up Dynamic Programming (Tabulation)

Instead of recursion, we build a DP table iteratively.

import java.util.*;

public class BooleanParenthesizationDP {

    public static int countWays(String s) {

        int n = s.length();

        int[][] trueWays = new int[n][n];

        int[][] falseWays = new int[n][n];

        for (int i = 0; i < n; i += 2) {

            trueWays[i][i] = (s.charAt(i) == 'T') ? 1 : 0;

            falseWays[i][i] = (s.charAt(i) == 'F') ? 1 : 0;

        }

        for (int len = 3; len <= n; len += 2) {

            for (int i = 0; i < n - len + 1; i += 2) {

                int j = i + len - 1;

                for (int k = i + 1; k < j; k += 2) {

                    int leftTrue = trueWays[i][k - 1];

                    int leftFalse = falseWays[i][k - 1];

                    int rightTrue = trueWays[k + 1][j];

                    int rightFalse = falseWays[k + 1][j];

                    char operator = s.charAt(k);

                    if (operator == '&') {

                        trueWays[i][j] += leftTrue * rightTrue;

                        falseWays[i][j] += leftFalse * rightTrue + leftTrue * rightFalse + leftFalse * rightFalse;

                    } else if (operator == '|') {

                        trueWays[i][j] += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;

                        falseWays[i][j] += leftFalse * rightFalse;

                    } else if (operator == '^') {

                        trueWays[i][j] += leftTrue * rightFalse + leftFalse * rightTrue;

                        falseWays[i][j] += leftTrue * rightTrue + leftFalse * rightFalse;

                    }

                }

            }

        }

        return trueWays[0][n - 1];

    }

    public static void main(String[] args) {

        String s = "T|F&T^T";

        System.out.println("Ways to parenthesize for True: " + countWays(s)); // Output: 4

    }

}