我有两个字符串:一个字一个字,另一个字母拼写字。我想知道这些争夺的字母是否有足够的字母来拼写这个单词。我已经提出了一个算法来做到这一点,但它不够有效,我希望我能得到一些帮助,使它更快。
这是我到目前为止所拥有的:
s1 = 'hypochondriac'
s2 = 'yqhpwoewnqlchpijcdrxpoa'
temp = list(s1)
for X in s2:
for Y in temp:
if X == Y:
temp.remove(X)
X = '@'
if temp == []:
print('Found ', s1)
我有一个问题,一旦X匹配我需要增加X但我不知道如何通过使它成为at符号将其从等式中取出。我尝试过使用break但是它没有达到足以打破s2循环的程度。无论哪种方式,我都非常确定这种双循环理念与具有一定经验的人相比会非常缓慢。有什么想法吗?
答案 0 :(得分:3)
您的代码效率不高,因为您在双循环中进行迭代。对于s1
中的每个字母,在最坏的情况下(无匹配),您将遍历所有s2
。
使用Counter
object代替;这些充当多集,您可以在O(1)时间内测试角色是否存在并管理剩余计数:
from collections import Counter
def contains(s1, s2):
s2set = Counter(s2)
for c in s1:
count = s2set[c]
if not c:
return False
if count == 1:
del s2set[c]
else:
s2set[c] = count - 1
return True
您也可以将s1
转换为多套装,并检查s2
的多套装是否包含每个条目的足够字母:
def contains(s1, s2):
s1set = Counter(s1)
s2set = Counter(s2)
for c, count in s1set.items():
if count > s2set[c]:
return False
return True
后者可以使用all()
function进一步缩小,如果传递的任何结果为False
,则提前False
,True
否则:{/} >
def contains(s1, s2):
s2set = Counter(s2)
return all(count <= s2set[c] for c, count in Counter(s1).items())
在所有这些中,您只需迭代s1
和s2
一次(直接或生成多套)。
后者的演示:
>>> from collections import Counter
>>> def contains(s1, s2):
... s2set = Counter(s2)
... return all(count <= s2set[c] for c, count in Counter(s1).items())
...
>>> s1 = 'hypochondriac'
>>> s2 = 'yqhpwoewnqlchpijcdrxpoa'
>>> contains(s1, s2)
True
>>> contains(s1 + 'b', s2)
False
答案 1 :(得分:2)
扩展@Martijn_Pieters解决方案,您可以这样使用Counter
:
from collection import Counter
def contains(s1, s2):
c1, c2 = Counter(s1), Counter(s2)
return all(c1[c] <= c2[c] for c in s1)
如果Counter[key]
不存在,您可以依赖key
默认返回0的事实。
答案 2 :(得分:0)
反过来做。从s2
:
s1 = 'hypochondriac'
s2 = 'yqhpwoewnqlchpijcdrxpoa'
temp = list(s2)
try:
for ch in s1:
temp.remove(ch)
except ValueError:
print("not found")
else:
print("found", s1)
答案 3 :(得分:0)
这是使用NumPy
-
import numpy as np
def in_string(s1,s2):
arr1 = np.fromstring(s1, dtype=np.uint8)
arr2 = np.fromstring(s2, dtype=np.uint8)
return np.in1d(arr1,arr2).all()
示例运行 -
In [50]: in_string('hypochondriac','yqhpwoewnqlchpijcdrxpoa')
Out[50]: True
# Let's add in a `z` at the end of first word which isn't in the scramble
In [51]: in_string('hypochondriacz','yqhpwoewnqlchpijcdrxpoa')
Out[51]: False
这是另一个使用np.searchsorted
-
def in_string_v2(s1,s2):
arr1 = np.fromstring(s1, dtype=np.uint8)
arr2 = np.fromstring(s2, dtype=np.uint8)
u1 = np.unique(arr1)
u2 = np.unique(arr2)
return ~(np.searchsorted(u2,u1) == np.searchsorted(u2,u1,'right')).any()
这是另一个一次处理一个单词列表的单词列表 -
def in_string_v3(list_s1,s2):
l_arr1 = np.fromstring("".join(list_s1), dtype=np.uint8)
arr2 = np.fromstring(s2, dtype=np.uint8)
lens = np.array(map(len,list_s1))
comp_lens = np.in1d(l_arr1,arr2).cumsum()[lens.cumsum()-1]
calc_lens = np.append(comp_lens[0],comp_lens[1:]-comp_lens[:-1])
return lens == calc_lens
示例运行 -
In [185]: ls1 = ['hypochondriac','hypochondriachsdhsahdsadhsa','hihfheifheozz']
In [186]: s2 = 'yqhpwoewnqlchpijcdrxpoadjksdgdkjsfkbdsfbdsdsaduiawyei'
In [187]: in_string_v3(ls1,s2)
Out[187]: array([ True, True, False], dtype=bool)
以另一种方式处理单词列表 -
def in_string_v4(list_s1,s2):
l_arr1 = np.fromstring("".join(list_s1), dtype=np.uint8)
arr2 = np.fromstring(s2, dtype=np.uint8)
lens = np.array(map(len,list_s1))
clens = lens.cumsum()
non_matching_idx = np.nonzero(~np.in1d(l_arr1,arr2))[0]
non_matching_grp = np.unique(clens.searchsorted(non_matching_idx))
return ~np.in1d(np.arange(len(list_s1)),non_matching_grp)