我们用count来表示未被匹配的左括号的数目。然后我们从左往右遍历每一个字符。显然,遇到左括号的时候count加一,遇到右括号的时候count减一。如果某一时刻发现count小于0了,说明有一个右括号注定在它之前找不到左括号与之匹配,那么为了“挽救”,我们只有唯一的对策:在之前某一个允许改动的地方将右括号改为左括号。这样的后果是count+=2。可见我们在遍历的过程中需要另外一个计数器,就是记录有多少个unlocked的右括号(以便于做所述的改动)。如果我们从左往右遍历完,count始终为正,那么说明所有的右括号(扣除那些必须改为左括号的右括号)都一定有与之配对的左括号。
同理,从左往右遍历,查看是否所有的左括号(扣除那些必须改为右括号的左括号)都一定有与之配对的右括号。如果Two Pass的check都通过的话,那么就可以返回true。
那么满足以上两个条件是否就是返回true的充要条件呢?事实上确实如此,你找不出反例。
本题其实就是LC 678的follow up。我们把那些unlocked的字符看成是星号,但是只允许替换成左括号或者右括号(不能设置为空)。
我们设置upper表示最多可能有多少个未被匹配的左括号,lower表示最少可能有多少个未被匹配的左括号。upper和lower的区别就在于对于那些待定字符如何处理:如果我们无脑设为'('的话,upper就会增1,如果无脑设为')'的话,那么lower就会减1. 另外,如果遇到那些locked的字符,那么upper和lower的增减就是一致的。
变化出现在如果发现lower<0的时候,那说明我们设置')'的策略过于激进,不能无脑地将所有待定字符设置为右括号。所以我们必须“让出”一个被变为右括号的星号,转而让其变为左括号。注意,这样一正一反的修正,lower就会增2.
判定的条件是:在遍历的过程中,如果任何时候发现upper<0,那么说明即使激进的设置左括号也不够用(与右括号匹配),就可以返回false。此外,最终为了表示平衡,lower必须为0. 如果lower大于0,说明“激进地加右括号”的策略也无法匹配所有的左括号,自然也是无解。