imashutosh51

Boolean Parenthesization

Mar 18th, 2026
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.61 KB | None | 0 0
  1. """
  2. Intuition for Boolean Parenthesization (Step-by-Step Breakdown)
  3.  
  4. Step 1: Identify the Problem Type
  5. ---------------------------------
  6. This is a variation of 'Matrix Chain Multiplication' (MCM). We are given
  7. an expression and we need to place brackets (parenthesize) in different
  8. ways to get a result. Whenever we have multiple ways to 'split' an
  9. expression, we think of the MCM pattern.
  10.  
  11. Step 2: Define the Range (i and j)
  12. ----------------------------------
  13. To solve any MCM-style problem, we need a left boundary 'i' and a
  14. right boundary 'j'.
  15. - s = "T ^ F & T"
  16. - i starts at 0 (first operand), j starts at n-1 (last operand).
  17.  
  18. Step 3: Finding the 'k' (The Split Point)
  19. -----------------------------------------
  20. Where can we break the expression? We can only break at the operators
  21. (^, &, |).
  22. - Operators are always at odd indices (1, 3, 5...).
  23. - So, our loop for 'k' will start at i+1 and go to j-1, incrementing
  24.  by 2 (k += 2) to always land on an operator.
  25.  
  26. Step 4: The Recursive 'Aha!' Moment
  27. ------------------------------------
  28. Unlike standard MCM where we just return one value (like min cost),
  29. here the result of an operator depends on both True and False values
  30. of its children.
  31. Example: For (Left) XOR (Right) to be True:
  32.   - Left must be True AND Right must be False
  33.   OR
  34.   - Left must be False AND Right must be True
  35.  
  36. Therefore, our function must ask for TWO things from every sub-problem:
  37. 1. Number of ways to make the left/right side TRUE.
  38. 2. Number of ways to make the left/right side FALSE.
  39.  
  40. Step 5: Base Cases
  41. ------------------
  42. - If i > j: Empty string, 0 ways.
  43. - If i == j: Single character.
  44.    - If target is True: return 1 if s[i]=='T' else 0
  45.    - If target is False: return 1 if s[i]=='F' else 0
  46.  
  47. Step 6: Combine Results (The Logic Gates)
  48. -----------------------------------------
  49. For every split at operator s[k], we calculate:
  50. - lT (Left True), lF (Left False)
  51. - rT (Right True), rF (Right False)
  52.  
  53. Based on s[k], we update our 'ans':
  54. - If '&':
  55.    - Ways to be True: lT * rT
  56.    - Ways to be False: (lT*rF) + (lF*rT) + (lF*rF)
  57. - If '|':
  58.    - Ways to be True: (lT*rT) + (lT*rF) + (lF*rT)
  59.    - Ways to be False: lF * rF
  60. - If '^':
  61.    - Ways to be True: (lT*rF) + (lF*rT)
  62.    - Ways to be False: (lT*rT) + (lF*rF)
  63.  
  64. Step 7: Optimization (Memoization)
  65. ----------------------------------
  66. Since (i, j, target) repeats many times in the recursion tree,
  67. we store the result in a map or a 3D array to avoid TLE.
  68. """
  69.  
  70. from math import inf
  71. def fun(s, i, j, dp, target):
  72.     if i > j:
  73.         return 0
  74.  
  75.     if i == j:
  76.         if target:
  77.             return 1 if s[i] == 'T' else 0
  78.         else:
  79.             return 1 if s[i] == 'F' else 0
  80.  
  81.     if dp[i][j][target] != -1:
  82.         return dp[i][j][target]
  83.  
  84.     ans = 0
  85.     for k in range(i+1, j, 2):
  86.         lt = fun(s, i, k-1, dp, True)
  87.         lf = fun(s, i, k-1, dp, False)
  88.         rt = fun(s, k+1, j, dp, True)
  89.         rf = fun(s, k+1, j, dp, False)
  90.         if s[k] == '&':
  91.             if target:
  92.                 ans += lt * rt
  93.             else:
  94.                 ans += lt * rf + lf * rt + lf * rf
  95.  
  96.         elif s[k] == '|':
  97.             if target:
  98.                 ans += lt * rt + lt * rf + lf * rt
  99.             else:
  100.                 ans += lf * rf
  101.  
  102.         else:  # '^'
  103.             if target:
  104.                 ans += lt * rf + lf * rt
  105.             else:
  106.                 ans += lt * rt + lf * rf
  107.  
  108.     dp[i][j][target] = ans
  109.     return ans
  110.  
  111. class Solution:
  112.     def countWays(self, s):
  113.         n = len(s)
  114.         dp = [[[-1]*2 for _ in range(n)] for _ in range(n)]
  115.         return fun(s, 0, n-1, dp, True)
Advertisement
Add Comment
Please, Sign In to add comment