在5 mb内存和5秒时间的限制下,如何在数组(python)中查找大量的唯一单词?
大家好,谁提出了我的问题。我试图解决一个问题,找到大量的独特单词,作为输入输入,第一个输入将是要输入的单词数量。这样地:在5 mb内存和5秒时间的限制下,如何在数组(python)中查找大量的唯一单词?,python,python-3.x,python-3.6,Python,Python 3.x,Python 3.6,大家好,谁提出了我的问题。我试图解决一个问题,找到大量的独特单词,作为输入输入,第一个输入将是要输入的单词数量。这样地: 五, 跟踪 失落的 鳞片 失落的 桌子 正确答案应该是:4 我尝试用Python解决这个问题,如下所示: a=set() x = int(input()) a.add(x) for i in range(x): y = input() a.add(y) print(len(a)-1) 它似乎工作得很好,只是在内存方面没有效率(在高输入时,它超过了内存限制)。
五,
跟踪
失落的
鳞片
失落的
桌子
正确答案应该是:4
我尝试用Python解决这个问题,如下所示:
a=set()
x = int(input())
a.add(x)
for i in range(x):
y = input()
a.add(y)
print(len(a)-1)
它似乎工作得很好,只是在内存方面没有效率(在高输入时,它超过了内存限制)。有没有更有效的方法来解决这个问题?我想到了两个解决方案。第一个是使用JSON结构。JSON结构使用一个唯一的键,然后,您可以创建这个结构,然后检查您有多少个键 代码将如下所示 对于这两个例子,我假设你有一个包含所有单词的数组,这个数组将是
words\u数组
unique_words={}
对于单词数组中的单词:
唯一_单词[word.lower().strip()]=1
#这个可以是任何值
#我只需要创建关键值
打印长度(唯一单词)
我使用了lower
和strip
来确保这个词是唯一的,无论它是大写还是空格
另一种方法是检查数组中是否已经存在单词,这种方法有效,但效率较低
unique_words=[]
对于单词数组中的单词:
w=word.lower().strip()
如果不是w,请使用唯一的单词:
唯一单词。附加(w)
打印长度(唯一单词)
我想如果你在寻找内存效率,我会建议其他替代方法,比如使用C,因为你使用的是Python 3.6+:使用
dict,而不是集合。尽管需要为每个元素存储一个值,dict
s即使在较旧的Python版本中,也经常使用较少的内存(它们针对不同的事情进行了优化;set
倾向于过度分配存储桶以降低存储桶冲突的风险,但这会消耗更多内存);在3.6+版本中,他们采用了更紧凑的dict
设计,只要唯一数据不太大,就可以节省更多的数据(当唯一项目的数量超过2**15
/32768时,set
s可以在某些尺寸上再次赢得胜利,因为此时紧凑性会显著下降)
因此,要改变它,只需执行以下操作:
a = {}
x = int(input())
for _ in range(x):
a[input()] = None
print(len(a))
另外,对于速度,如果您不需要使用输入
,您可能应该避免使用它,直接从sys.stdin
读取<代码>输入
会对输出进行大量不必要的刷新,以及其他您在此处并不真正需要的工作。因此,这样做可能会更快:
import itertools, sys
x = int(input())
a = dict.fromkeys(itertools.islice(sys.stdin.buffer, x))
print(len(a))
它只需直接拉动线路而不进行修改,并将线路直接推入C级的dict
,以提高速度。将sys.stdin
更改为sys.stdin.buffer
以避免对字符串进行解码,并将map(str.rstrip,…)
或map(bytes.rstrip,…)
包装为sys.stdin.buffer
以删除换行(如果最后一行可能不以换行结束,这对于正确性是必要的,我想它节省了少量内存)
如果输入可能很大(更高的五位数唯一输入),那么dict
可能不会有帮助,所以只需坚持使用set
,但您仍然可以使用sys.stdin
优化,最终形成如下形式:
x = int(input())
a = set(itertools.islice(map(bytes.rstrip, sys.stdin.buffer), x))
print(len(a))
根据数据的预期性质:
- 对于字典中的单词,尤其是相似的单词,请使用trie
- 对于长文本,使用无损压缩
zlib压缩示例:
import zlib
a = set()
x = int(input())
for _ in range(x):
a.add(zlib.compress(input().encode()))
#a.add(input())
print("unique: ", len(a))
print("memory: ", sum(len(b) for b in a))
未压缩:
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique: 2
memory: 32
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique: 2
memory: 22
压缩:
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique: 2
memory: 32
> echo -e "3\naaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbb\naaaaaaaaaaaaaaaa" | python3 c.py
unique: 2
memory: 22
是的,为什么不呢?它是一个集合,所以只存储唯一的单词。最后我计算集合的长度,并减去一个,因为第一次输入(总共的单词数)不应该被计算。为什么还要将从用户处读取的单词数添加到a
?如果避免这种情况,len(a)-1
可以缩短为len(a)
x
无需保存到任何集合
。同意@DerteTrdelnik-trie将节省大量内存。这是因为,与集合
不同,trie可以存储例如“水下”和“内衣”,而无需存储两份“内衣”。抱歉,删除了我的评论,因为我看到了另一条关于保留50万字的评论-我不确定询问者是否在某些挑战中使用了正确的工具..因为python在challangesBTW上优化时间和空间时不是最好的,只是为了量化从移动到字节
:在64位CPython,每个str
需要额外16个字节的内存(如果空的str
不是单字节,则需要49个字节,而等效的bytes
对象需要33个字节,每个额外的字符为每个对象增加一个字节)。如果输入是带有非ASCII字符的utf-8
编码文本,则成本可能会显著增加(基本开销会增加,对于非拉丁-1字符,每个字符的成本也会增加一倍或四倍)。每个单词zlib
压缩有助于你传递实际单词的几率基本为零。你构建的假词恰巧压缩得非常好,但英语单词遵循一些已知的模式,而这些模式在给定单词中重复出现的几率足以让zlib
让你受益基本上是零。trie至少可以提供一些单词间的状态,并可能节省内存;提供一个这样的例子,而不是zlib
,这基本上保证是无用的。@ShadowRanger同意,对于普通英语单词,我也建议使用trie,但对于随机单词(例如一些生成的ID)或一般文本(t