Write the function to count the number of ways of parenthesizing the expression
Problem
Given a boolean expression consisting of the symbols 0,1, &, |, and ^, and a
desired boolean result value result, implement a function to count the number
of ways of parenthesizing the expression such that it evaluates to result.
Example)
Expression: 1^0|0|1
Desired result: false (0)
Output: 2 ways. 1^( (0|0)|1) and 1^(0|(0|1)).
This is the last questions from "Cracking Coding" for Recursion & Dynamic programming.
I guess this book call "Memoization" part of Dynamic programming, a dynamic programming, which is not actually correct.
Basic recursion approach
Upshot
Coming up with the recursion pattern for this problem is to first find the very high level view of the problem.
Given expression, 1^0|0|1 and expected value, e, we can see the following basic cases:
# of ways to put parentheses = count( 1^(0|0|1), e) + count( (1^0)|(0|1), e ) + count( (1^0|0)|1), e )
Recursively, count( 1^(0|0|1), e) = count(1, e) $\times$ count(0|0|1, e) etc.
Each time we break up the expression into two parts and call count on each part recursively.
Cases for each operand
Now, let's consider the possible cases for operands
For OR operator, "|", we consider both e = true and e = false.
Case 1) e = true, we consider three possible cases:
TRUE | TRUE, TRUE | FALSE, FALSE | TRUE
count( expr1 | expr2, true) = count(expr1, true) $\times$ count(expr2, true) + count(expr1, true) $\times$ count(expr2, false) + count(expr1, false) $\times$ count(expr2, true)
Case 2) e = false, we consider one possible case:
FALSE | FALSE
count( expr1 | expr2, false) = count(expr1, false) $\times$ count(expr2, false)
For AND operator, "&", we also consider both e = true and e = false.
Case 1) e = true, we consider one possible case:
TRUE & TRUE
count( expr1 & expr2, true) = count(expr1, true) $\times$ count(expr2, true) + count(expr1, true) $\times$ count(expr2, false) + count(expr1, false) $\times$ count(expr2, true)
Case 2) e = false, we consider three possible cases:
FALSE & FALSE, TRUE & FALSE, FALSE & TRUE
count( expr1 & expr2, false) = count(expr1, true) $\times$ count(expr2, false) + count(expr1, false) $\times$ count(expr2, true) + count(expr1, false) $\times$ count(expr2, false)
Lastly, for XOR operator, "^", we also consider both e = true and e = false.
Case 1) e = true, we consider two possible cases:
TRUE ^ FALSE, FALSE ^ TRUE
count( expr1 & expr2, true) = count(expr1, true) $\times$ count(expr2, false) + count(expr1, false) $\times$ count(expr2, true)
Case 2) e = false, we consider two possible cases:
TRUE ^ TRUE, FALSE ^ FALSE
count( expr1 & expr2, false) = count(expr1, true) $\times$ count(expr2, true) + count(expr1, false) $\times$ count(expr2, false)
Now, we are ready to write the first algorithm, which will run in $O(N \times N!)$
Here is the complete code using recursion.
More efficient recursion with Memoization
Previous algorithm process the same problems repeated during the recursion.
We can avoid this duplications by caching the intermediate results in the lookup table.
The following code uses the Memoization. Only difference is the routine checking the std::map before perform the recursion and adding the resultant count to the std::map before returning the count at the end of the function.
Comments
Post a Comment