如果标题不够准确,请道歉。
我有一个程序可以在字符串中搜索元音,但它会在字符串中特定大小的滑动窗口上进行。我想计算元音的密度。假装我不在乎有空白和符号;它就在那里。我编码的显而易见的解决方案如下:
s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit ... consequat."
# assume s continues after the "..."
v = "aeiou"
v_dict = {}
max_win_size = 100
if max_win_size > len(s): max_win_size = len(s)
for i in range(1, max_win_size):
v_dict[i] = {}
for j in range(0, i+1):
v_dict[i][j] = 0 # set counts to zero
for j in range(1, len(s)-i+1):
s_slice = s[j:j+i].lower()
v_count = sum([s_slice.count(c) for c in v])
v_dict[i][v_count] += 1
这最终给出了从1到字符串大小的不同滑动窗口的元音频率。这个程序按我的意愿工作,但问题是它很慢。它显然是二次的,我想提高效率,因为随着文本变大,程序需要花费更多的时间。问题是我不确定如何将问题空间转换为更有效的算法。
有没有人对如何制作这个,比如说,使用loglinear?
编辑:
我尝试了由cr1msonB1ade实施的Ben Voigt的答案。它像宣传的那样工作。此外,我认为我会将经验证据包含在速度声明中。
首先是增加字符串大小的运行时间。这两个函数都是线性执行的,但是使用纯python实现它的开销导致线性运行时间的系数明显增大。
其次是增加窗口大小的运行时间。我修改了窗口大小并运行越来越大的窗口大小。这一次,我的函数的二次率显示出来,而numpy累积和函数保持线性。
答案 0 :(得分:3)
根据累积计数重写算法。
位置i
和j
(包括)之间的出现次数仅为cumul_count(j) - cumul_count(i-1)
,并且所需的计算量不会随窗口大小而增加。
答案 1 :(得分:2)
就理论运行时而言,您计算max_win_size * (len(s)-max_win_size+1)
值,因此无法在o(max_win_size*len(s))
运行时间之后获得。
就实际计算运行时而言,您当前的代码存在一些问题。首先,没有理由在每个字符串上进行字母匹配。您应该首先将字符串转换为TRUE
FALSE
列表,然后再查询。
其次,您可以在移动滑动窗口时动态更新总和。换句话说,您只需查询要删除的字母和要添加的字母,即可获得下一个子字符串中的元音数。
另外,您并不需要为数据结构的第二级提供字典。您确切知道列表的长度,并且您将使用整数值进行索引,因此只需使用列表。
我确定可以添加一些其他效率,但我们将这些效果放在一起:
s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit ... consequat."
# assume s continues after the "..."
v = list("aeiou")
isVowel = [l in v for l in s]
v_dict = {}
max_win_size = 100
if max_win_size > len(s): max_win_size = len(s)
for i in range(1, max_win_size):
v_dict[i] = [0,] * (i+1)
curr_vowels = sum(isVowel[:i])
v_dict[i][curr_vowels] += 1
for curr_pos in range(1, len(s)-i):
# add next letter position and subtract letter falling out of window
curr_vowels += isVowel[curr_pos + i] - isVowel[curr_pos - 1]
v_dict[i][curr_vowels] += 1
编辑:使用累积方法@Ben建议:
import numpy as np
s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit ... consequat."
# assume s continues after the "..."
v = list("aeiou")
cumVowels = [0,] + np.cumsum([l in v for l in s])
v_dict = {}
max_win_size = 100
if max_win_size > len(s): max_win_size = len(s)
for i in range(1, max_win_size):
v_dict[i] = [0,] * (i+1)
for pos in range(0, len(s)-i):
v_dict[i][cumVowels[pos + i] - cumVowels[pos]] += 1