如何解决可能具有最佳时间复杂度的字母汤问题
我在数据结构课程练习中遇到了以下问题(字母汤)。
https://github.com/kennedyCzar/AlphabetSoup-Using-Django
我在 O(m+s) 中解决了它,其中 m 是消息的长度,s 是汤的长度(我刚刚从汤中创建了一个表,并决定是否可以使用它来创建消息表)
def checkBowl(message,soup):
d = {}
# O(S)
for c in soup:
d[c] = d.get(c,0) + 1
# O(m)
for c in message:
if(d.get(c,0) == 0):
return False
else:
d[c] -= 1
# So the overall time complexity is O(m+s)
return True
但似乎给定的 GitHub 在 O(mlogm) 中解决了它,但是我认为他/她的解决方案是在 O(m*s) 中,因为他/她只是没有考虑 Python 的操作符在 O(长度的列表)。
顺便说一下,有人可以提示一下,是否有可能以更好的时间复杂度解决这个问题? (问题说明这碗汤可能很大)
解决方法
正如您所说,链接算法对于消息中的每个字母,都会遍历整个汤以找到该字母。如果找到该字母,则将其从汤中取出。因此时间复杂度为 O(m * S)
。
您的算法是 O(m + S)
,因为您只对汤进行了一次迭代。所以你的解决方案更好。
但是如果汤很大怎么办?无限汤呢?如果汤是一个无限生成器,即使汤的第一个字母是消息本身,您也永远无法完成字典的构建。
这引出了一个想法:为什么不在得到消息的字母之前迭代汤的字母?在这种情况下,您将阅读信件,直到您能够撰写邮件并在邮件完成后立即停止:
import collections
def check_bowl2(message,soup):
# O(m)
message_letters = collections.Counter(message)
# O(S)
for c in soup:
if c not in message_letters: # we don't need `c`
pass
elif message_letters[c] == 1:
del message_letters[c] # we won't need `c` anymore
if not message_letters: # we found all letters
return True
else: # we still need `c`,but one less time
message_letters[c] -= 1
return False
时间复杂度仍然是O(m + S)
,但空间复杂度降低了:O(m)
vs O(S)
。当然,如果你在同一个汤里寻找很多消息,构建 dict 仍然是最好的选择。
我认为您找不到比 O(S)
更快的算法:在最坏的情况下(没有消息),您必须至少遍历整个汤一次。
我不认为你可以解决这个问题,因为如果不解析一个字母就不可能检查它是否属于字母汤,而且你显然必须解析你的消息。
但是,您的解决方案仅在 AVERAGE 上是线性的,因为哈希映射仅平均具有恒定的复杂性。所以你最坏情况的复杂度更像是 O(s^2+s.m)。
你可以使用你自己的数据结构来改进它,例如,不依赖于哈希而是二叉树,以实现 O(s.log(s)+ m.log(s)) 的最坏情况复杂度。>
编辑:您也可以利用您的字符只是 ASCII 字符这一事实。
def checkBowl(message,soup):
d = [0 for i in range(128)]
# O(S)
for c in soup:
d[ord(c)] +=1
# O(m)
for c in message:
if(d[ord(c)] == 0):
return False
else:
d[ord(c)] -= 1
# So the overall time complexity is O(m+s)
return True
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。