我的问题是参考FB HackerCup 2013 QualificationRound问题 - BalancedSmileys。
问题陈述:https://www.facebook.com/hackercup/problems.php?pid=403525256396727&round=185564241586420(此处也可复制:https://github.com/anuragkapur/Algorithmic-Programming/tree/master/src/com/anuragkapur/fb/hackercup2013/qr#problem-2-balanced-smileys)
我想到了如何使用具有指数运行时间的BruteForce方法来解决这个问题。
根据发布的官方解决方案,有一个线性运行时间的解决方案。这里描述:https://www.facebook.com/notes/facebook-hacker-cup/qualification-round-solutions/598486173500621
基本上,它维护着两个计数器:minOpen和maxOpen。每当遇到一个开括号“(”,maxOpen就会增加。如果“(”不是笑脸的一部分,minOpen也会递增。处理类似的策略“)”,如上面的解释链接所述。
我可以看到线性时间方法有效,但在我脑海中却不是很清楚 - 如何?因此,我正在对这个小组进行调查,以确定是否有人可以对线性运行时间解决方案进行替代“解释”。
非常感谢!
答案 0 :(得分:1)
预处理:对输入进行标记化,并将每个标记转换为包含对左括号计数的可能影响的列表。
输入
i am sick today (:()
:(:))
成为
[[0], [0], ..., [0], [1], [0, 1], [-1]]
[[0, 1], [-1, 0], [-1]]
。现在,你的暴力算法是这样的。
def solution1(lst, opencnt=0, i=0):
if opencnt < 0:
return False
elif i >= len(lst):
return opencnt == 0
else:
for delta in lst[i]:
if solution1(lst, opencnt + delta, i + 1):
return True
return False
函数solution1
始终为给定输入提供相同的输出。对于{-1,0,1}中具有条目的给定lst
,opencnt
(-1到len(lst)
)和{{1}中的每一个都只有线性数量的可能性。 }(0到i
),所以通过缓存给定输入的输出,即memoizing,我们得到二次时间算法。
线性时间算法将控制流内部转出。我们不是对每个len(lst) - 1
进行单独的递归调用,而是将delta
设为一组。
opencnt
此实现还不是线性时间。最后的优化是{{1}}始终是一个区间,即[minOpen,maxOpen],并且可以在恒定时间内进行操作。
答案 1 :(得分:1)
如果它不适用于规则#2中的冒号,那么显而易见的算法将是具有两个状态的有限状态机,它循环遍历字符串并保持括号计数:
pcount = 0
pcount++
pcount--
if pcount > 0
,否则立即返回“NO”规则#2允许冒号的事实使得它更具挑战性,因为形式为“(:)”或者说“(foo :)”的消息也可以被认为具有平衡的括号。这个规则基本上说的是“你发现很难判断一个括号是否真的是一个括号或一个表情符号的一部分”,你应该确定“有一种方法来解释他的信息,同时保持括号平衡”。 / p>
更明确地说:我们实际上并不关心表情符号。我们会发现括号是否可以平衡。
天真的方法是维护一组括号计数器。最初,它只包含一个括号计数器。每次遇到'('或')'时,都会将当前括号计数器数组附加到自身,按照上面简单算法的建议在前半部分中递减/递减。到达字符串的末尾后,检查数组是否包含零。如果是这样,那么字符串有一种方法可以被视为具有平衡的括号。否则,就没有。
这个第二个算法可能还有改进的余地,如果消息包含1000个括号,甚至可能会有一个令人惊讶的优雅解决方案,它不会耗尽内存。但是,如果有足够的RAM,这种天真的方法将在线性时间内确定正确答案(而且,遗憾的是,指数空间)。