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 | TRUETRUE | FALSEFALSE 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 & FALSETRUE & FALSEFALSE & 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

Popular posts from this blog

Planting flowers with no adjacent flower plots

Stock price processing problem