Let's use example 0 from the writeup to illustrate. The string is:
( ) ( ) ( ) ( ) ( )
i | String with deleted characters in orange | Legal and do recursion? |
1 | ( ) ( ) ( ) ( ) ( ) | Yes | 3 | ( ) ( ) ( ) ( ) ( ) | No | 5 | ( ) ( ) ( ) ( ) ( ) | No | 7 | ( ) ( ) ( ) ( ) ( ) | No | 9 | ( ) ( ) ( ) ( ) ( ) | No |
It should be pretty clear that this one's answer is going to be one. Let's try example 2 to show one with more recursion. Here's the string:
( ( ( ) ( ) ( ) ) )
i | String with deleted characters | Legal and do recursion? |
3 | ( ( ( ) ( ) ( ) ) ) | Yes | 5 | ( ( ( ) ( ) ( ) ) ) | Yes | 7 | ( ( ( ) ( ) ( ) ) ) | Yes | 8 | ( ( ( ) ( ) ( ) ) ) | Yes | 9 | ( ( ( ) ( ) ( ) ) ) | Yes |
If you still need some more detail, here's example two run to completion -- for each string, I'll print the recursive calls that it makes, and the final values:
s: () Returns 1 Calls: :1 s: (()) Returns 2 Calls: ():1 ():1 s: ((())) Returns 6 Calls: (()):2 (()):2 (()):2 s: ()() Returns 1 Calls: ():1 s: (()()) Returns 4 Calls: (()):2 ()():1 ()():1 s: ((()())) Returns 18 Calls: ((())):6 (()()):4 (()()):4 (()()):4 s: ()(()) Returns 2 Calls: (()):2 s: (()(())) Returns 12 Calls: ((())):6 ()(()):2 ()(()):2 ()(()):2 s: ()()() Returns 1 Calls: ()():1 s: (()()()) Returns 8 Calls: (()()):4 ()(()):2 ()()():1 ()()():1 s: ((()()())) Returns 54 Calls: ((()())):18 (()(())):12 (()()()):8 (()()()):8 (()()()):8
/* Topcoder SRM 714, D2, 500-pointer. RemovingParenthesis James S. Plank Mon May 15 15:56:16 EDT 2017 */ #include <string> #include <map> #include <iostream> #include <cstdio> #include <cstdlib> using namespace std; class RemovingParenthesis { public: int countWays(string s); map <string, int> C; }; int RemovingParenthesis::countWays(string s) { int i, j; int legal; // Is the new string legal? int level; // Use this to keep track of nesting level when testing for legality. int total; // Sum of all recursive calls. string s2; // The string that we build from deleting characters 0 and i. /* Base case -- return 1 for the empty string. */ if (s.size() == 0) return 1; /* Check the cache to see if you've solved this one already. */ if (C.find(s) != C.end()) return C[s]; total = 0; /* Run through each character starting with i=1. If the character is a right paren, then construct s2 by deleting characters 0 and i. Use substr() to do this. */ for (i = 1; i < s.size(); i++) { if (s[i] == ')') { s2 = (s.substr(1, i-1) + s.substr(i+1)); /* Now test s2 for legality */ legal = 1; level = 0; for (j = 0; j < s2.size(); j++) { if (s2[j] == '(') { level++; } else { level--; } if (level < 0) legal = 0; } /* The constraints guarantee that level will = 0 at the end of the loop above. If they didn't, I should make sure that level equals 0 here. */ /* If it's legal, then make the recursive call. */ if (legal) total += countWays(s2); } } /* Memoize and return at the end. */ C[s] = total; return total; } |