如何编写状态机解决Count the smiley faces问题并修复运行报错
Count the smiley faces 状态机实现问题排查与修复
题目规则
接收数组arr作为入参,完成countSmileys函数,返回数组中笑脸的总数量。
笑脸规则:
- 每个笑脸必须包含有效眼睛,有效眼睛标记为
:或;- 笑脸可选择性添加鼻子,有效鼻子字符为
-或~- 每个笑脸必须包含微笑嘴部,有效嘴部标记为
)或D
除上述字符外不允许出现其他额外字符,且笑脸的眼睛、鼻子、嘴部顺序固定。
有效笑脸示例::) :D ;-D :~)
无效笑脸示例:;( :> :} :]
用例示例countSmileys([':)', ';(', ';}', ':-D']); // 应返回 2; countSmileys([';D', ':-(', ':-)', ';~)']); // 应返回 3; countSmileys([';]', ':[', ';*', ':$', ';-D']); // 应返回 1;注意事项
空数组作为入参时返回0,输入始终为合法数组,无需处理非数组输入。
错误原因排查
- 状态变量作用域错误:
state定义在filter回调外部,所有笑脸共享同一个状态实例。当第一个笑脸处理完成后,state可能变为布尔值true,处理下一个笑脸时调用state(s)就会触发TypeError: state is not a function错误。 - 状态返回逻辑缺陷:
- 匹配到有效嘴部后直接返回布尔值
true,如果当前笑脸存在多余的后续字符,下一轮循环会尝试调用布尔值执行,直接报错 - 匹配失败的分支返回
undefined,同样会触发非函数调用错误
- 匹配到有效嘴部后直接返回布尔值
- 边界场景缺失处理:笑脸合法长度仅为2或3位,超出长度的字符串直接判定为无效,现有逻辑没有对应校验。
修复方案
调整状态作用域,补充无效状态处理,增加长度校验,修复后代码如下:
function countSmileys(smileys) { // 定义无效状态,所有非法匹配都进入该状态 const invalid = () => invalid; function smileyHasValidEye(s) { if (s === ':' || s === ';') { return smileyHasValidNose; } return invalid; } function smileyHasValidNose(s) { if (s === '-' || s === '~') { return smileyHasValidMouth; } // 没有鼻子的情况,直接校验当前字符是否是嘴部 return smileyHasValidMouth(s); } function smileyHasValidMouth(s) { if (s === ')' || s === 'D') { // 匹配到嘴部后,后续不能再有任何字符,进入待完成状态 return complete; } return invalid; } // 匹配完成状态,后续有字符就变为无效 const complete = () => invalid; return smileys.filter(smiley => { // 每个笑脸单独初始化状态 let state = smileyHasValidEye; // 先做长度校验,非2/3位直接无效 if (smiley.length < 2 || smiley.length >3) return false; for (let s of [...smiley]) { state = state(s); } // 最终状态必须是完成状态才算有效 return state === complete; }).length; } // 测试用例 console.log(countSmileys([':)', ';(', ';}', ':-D'])); // 输出2 console.log(countSmileys([';D', ':-(', ':-)', ';~)'])); // 输出3 console.log(countSmileys([';]', ':[', ';*', ':$', ';-D'])); // 输出1
内容的提问来源于stack exchange,提问作者Ha0ran
相关产品推荐
相关产品推荐

