Python 可能具有最佳时间复杂度的字母汤问题
作为我的数据结构课程练习,我得到了以下问题(字母汤) 我在O(m+s)中解决了这个问题,其中m是消息的长度,s是soup的长度(我刚刚从soup中创建了一个表,并决定是否可以使用该表创建消息)Python 可能具有最佳时间复杂度的字母汤问题,python,algorithm,data-structures,Python,Algorithm,Data Structures,作为我的数据结构课程练习,我得到了以下问题(字母汤) 我在O(m+s)中解决了这个问题,其中m是消息的长度,s是soup的长度(我刚刚从soup中创建了一个表,并决定是否可以使用该表创建消息) 但是似乎给定的GITHUB在O(mLogm)中解决了它,但是我认为他/她的解决方案在O(m*s)中,因为他/她没有考虑Python的操作符在O中(列表的长度)。 顺便问一下,有人能不能提示一下,这有可能以更好的时间复杂度解决这个问题?(问题说明这碗汤可能非常大)我认为你不能在这个问题上走到线性以下,因为
但是似乎给定的GITHUB在O(mLogm)中解决了它,但是我认为他/她的解决方案在O(m*s)中,因为他/她没有考虑Python的操作符在O中(列表的长度)。
顺便问一下,有人能不能提示一下,这有可能以更好的时间复杂度解决这个问题?(问题说明这碗汤可能非常大)我认为你不能在这个问题上走到线性以下,因为不分析字母汤就无法检查字母是否属于字母汤,而且你显然必须分析你的信息 但是,您的解决方案平均而言是线性的,因为哈希映射平均而言具有恒定的复杂性。因此,最坏情况的复杂性更像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
我不认为你能在这个问题上走到线性以下,因为不分析一个字母是否属于字母汤是不可能的,而且你显然必须分析你的信息 但是,您的解决方案平均而言是线性的,因为哈希映射平均而言具有恒定的复杂性。因此,最坏情况的复杂性更像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
如您所述,对于消息中的每个字母,链接算法都会在soup上迭代以查找字母。如果找到了字母,则会将其从汤中取出。因此,时间复杂度为
O(m*S)
您的算法是O(m+S)
,因为您只在汤上迭代一次。所以你的解决方案更好
但是如果汤很大怎么办?来一份无限汤怎么样?如果soup是一个无限生成器,那么即使soup的第一个字母是消息本身,您也永远无法完成词典的构建
这就引出了一个想法:为什么不反复检查汤的字母,直到您得到消息的字母?在这种情况下,您将阅读信件,直到您能够编写邮件,并在邮件完成后立即停止:
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)
与O(S)
。当然,如果您正在同一个汤中查找许多消息,那么构建dict仍然是最佳选择
我认为你不会找到比O(S)更快的算法:在最坏的情况下(没有消息),你必须至少在整个汤中迭代一次。如你所述,链接算法会对消息中的每个字母在汤中迭代以查找字母。如果找到了字母,则会将其从汤中取出。因此,时间复杂度为
O(m*S)
您的算法是O(m+S)
,因为您只在汤上迭代一次。所以你的解决方案更好
但是如果汤很大怎么办?来一份无限汤怎么样?如果soup是一个无限生成器,那么即使soup的第一个字母是消息本身,您也永远无法完成词典的构建
这就引出了一个想法:为什么不反复检查汤的字母,直到您得到消息的字母?在这种情况下,您将阅读信件,直到您能够编写邮件,并在邮件完成后立即停止:
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)
与O(S)
。当然,如果您正在同一个汤中查找许多消息,那么构建dict仍然是最佳选择
我认为你不会找到比O(S)更快的算法:在最坏的情况下(没有消息),你必须在整个汤中至少迭代一次。哦,对了。我完全忘记了哈希表在最坏情况下的复杂性是O(n)。谢谢:)但是通过使用堆这一完整的二叉树,顺序将是O(s.log(s)+m.log(m)),而不是O(s.log(s)+m.log(s))。我说得对吗?我的意思是你在答案的最后一行打错了,或者我误解了使用二叉树的解决方案。@Me。我在考虑一个解决方案,其中与当前解决方案的唯一区别是映射实现,使用树覆盖散列。你对解决方案的想法是什么?我会尽快去做possible@Me. 完成了,真的很好,对吧。我完全忘记了哈希表在最坏情况下的复杂性是O(n)。谢谢:)但是通过使用堆这一完整的二叉树,顺序将是O(s.log(s)+m.log(m)),而不是O(s.log(s)+m.log(s))。我说得对吗?我的意思是你在答案的最后一行打错了,或者我误解了使用二叉树的解决方案。@Me。我在考虑一个解决方案,其中与当前解决方案的唯一区别是映射实现,使用树覆盖散列。你对解决方案的想法是什么?我会尽快去做possible@Me. 完成了,真正的线性是的,正如我提到的,问题是“这可能是一碗包含许多字母的非常大的汤”,你的解决方案以某种方式解决了这个问题。但是在最坏的情况下访问字典O(1)还是O(n)?我的意思是,正如@TUI lover所提到的,最坏的情况是O(n),所以复杂度应该是O(mS),对吗?正如@TUI lover所说,对于字典来说,最坏的情况是
O(n)
。但是在您的例子中,您可以假设