The problem confused me as well until I understood that smileys can be separated into a colon and a parentheses if required (because a colon as the text says is also a valid character.) Now you can write a linear algorithm. By counting how many brackets are open, how many could be opened by smileys and how many could be closed by smileys:
int main() {
int n; string s;
getline(cin,s); n = stoi(s); // get value of n
for(int i = 0; i < n; i++){
getline(cin,s); // read line
ll open = 0, smiopen = 0, smiclose = 0;
bool colon = false; // was the last character a colon?
bool balanced = true;
for(ll j = 0; j < s.size(); j++){
if(colon){
if(s[j] == '(') smiopen++; //you COULD open an expr.
if(s[j] == ')' && open > 0) {open--; smiclose++;} // you COULD close an expr.
}else{
if(s[j] == '(') open++; // you HAVE TO open an expr.
if(s[j] == ')') { // you HAVE TO close an expr.
if(open > 0) open--;
else if(smiopen > 0) smiopen--; //open an optional expr. for balance
else if(smiclose > 0) smiclose--; //unclose optional close
else{ balanced = false; break;} //not possible to match found ')'
}
}
colon = false;
if(s[j] == ':') colon = true;
}
if(balanced && open == 0) cout << "YES"<<endl;
else cout << "NO"<<endl;
}
}
You might notice smiopen
and smiclose
could be fused into one variable. But I separated them for clarity.
:)
, you can treat it as either parenteses or not, and your depth can either remain the same or decrease by 1. Now note that at any point, possible numbers form an interval. Interval update rules are simple. When you see)
:[a, b] -> [a-1, b-1]
. When you see:)
:[a, b] -> [a-1, b]
(since you can ignore parentheses, the upper bound doesn't decrease).(
and:(
are similar $\endgroup$ – Dmitry Jul 11 '20 at 10:57