facebook hacker cup 2013资格赛第二题
一个递归算法
bool isbalance(字符串s,未匹配的左括号数unmatched, 当前要考察的字符位置idx)
(1)考察字符串s从idx开始到末尾的子字符串,若为空或只包含一个字符,讨论可得,是边界情况
(2)否则,考察子字符串前两个字符,即s[idx]和s[idx+1],如果是笑脸或哭脸,考虑两种可能性,解释为表情或左右括号,记录未匹配的左括号数;若为其他字符,相应考虑unmatched是否改变,idx加1或2,递归
(递归函数保证:当s[idx] == ‘)’或’(’时,s[idx-1]不为’:’,即处理从idx开始的子字符串时,不必考虑s[idx-1])
下面是完整代码:
#include <stdio.h> #include <string> #include <iostream> using namespace std; bool isbalance(string &s, int unmatched, int idx) { if(idx >= s.length()){ if (unmatched == 0) { return true; } else { return false; } }else if (idx == s.length() - 1) { if (s[idx] == '(') { return false; }else if(s[idx] == ')'){ if(unmatched == 1){ return true; }else{ return false; } }else{ if (unmatched == 0) { return true; } else { return false; } } }else{//have at least two chars if (s[idx] == ':') { if (s[idx + 1] == ':') { return isbalance(s, unmatched, idx + 1); } else if(s[idx + 1] == '('){ return isbalance(s, unmatched, idx + 2) || isbalance(s, unmatched + 1, idx + 2); } else if (s[idx + 1] == ')') { if (unmatched == 0) { return isbalance(s, unmatched, idx + 2); } else { return isbalance(s, unmatched, idx + 2) || isbalance(s, unmatched - 1, idx + 2); } } else { return isbalance(s, unmatched, idx + 2); } }else if (s[idx] == '(') { return isbalance(s, unmatched + 1, idx + 1); }else if(s[idx] == ')'){ if (unmatched == 0) { return false; }else{ return isbalance(s, unmatched - 1, idx + 1); } }else{ return isbalance(s, unmatched, idx + 1); } } } //保证当s[idx] == ')'或'('时,s[idx-1] != ':' int main(int argc, const char *argv[]) { freopen("balanced_smileystxt.txt", "r", stdin); freopen("out2.txt", "w", stdout); int T; string s; cin >> T; getline(cin, s); for (int i = 1; i <= T; i++) { getline(cin, s); if (isbalance(s, 0, 0)) { printf("Case #%d: YES\n", i); }else { printf("Case #%d: NO\n", i); } } return 0; }
一个线性算法
记左括号、哭脸‘:(’、右括号、笑脸’:)’个数分别为left, lface, right, rface
总是优先识别为笑脸和哭脸
从左到右扫描字符串,
(1)每次遇到左括号,left++;
(2)每次遇到lface,lface++
(3)每次遇到一个右括号可以直接让左括号--(如果左括号个数>0),如果此时左括号为0,让lface--(如果lface>0),否则,不平衡
(4)每次遇到rface,如果left和lface都为0,什么也不做(rface表示能够解释为右括号的笑脸的个数),否则,rface++
所以关键是为每个右括号配上左括号,和为每个左括号配上一个右括号;当“不构成笑脸“的右括号出现的时候,立即配对;最后检查左括号能否成功配对:left小于等于可以解释为右括号的笑脸数,即left<=rface
(因此,实际上right变量基本用不到)
bool isbalance(string s) { int left = s[0] == '(', right = s[0] == ')', lface = 0, rface = 0; if (right == 1) { return false; } for (int i = 1; i < s.length(); i++) { switch (s[i]){ case '(': if (s[i - 1] == ':') { lface++; } else { left++; } break; case ')': if (s[i - 1] == ':') { if (left != 0 || lface != 0) {//means that this ':)' can be interpreted as ':' and ')' rface++; }//else do nothing } else { if (left > 0) { left--; } else {//left==0 if (lface > 0) { lface--; } else {//lface == 0 return false; } } } break; } } //至此,右括号均匹配成功 if (left <= rface) {//左括号也匹配成功 return true; } else { return false; } }