我正在进行文本挖掘,并尝试清理弹幕(弹幕)数据。(子弹幕是视频网站中的一种注释)我的数据中有很多重复的表达式。 (“ LOL LOL LOL”,“ LMAOLMAOLMAOLMAO”。)我想获得“ LOL”,“ LMAO”。
在大多数情况下,我想找到序列的最小周期。
转角情况:输入序列的尾部可以看作是周期性子序列的一部分。
"eat an apple eat an apple eat an" # input
"eat an apple" # output
还有其他一些测试用例:
cases = [
"abcd", #4 abcd
"ababab", #2 ab
"ababcababc", #5 ababc
"abcdabcdabc", #4 abcd
]
注意:至于最后一种情况“ abcdabcdabc”,“ abcd”优于“ abcdabcdabc”,因为最后三个字符“ abc”是“ abcd”的一部分。
def solve(x):
n = len(x)
d = dict()
T = 0
k = 0
while k < n:
w = x[k]
if w not in d:
d[w] = T
T += 1
else:
while k < n and d.get(x[k], None) == k%T:
k += 1
if k < n:
T = k+1
k += 1
return T, x[:T]
对于前两种情况,它可以输出正确的答案,但无法全部解决。
答案 0 :(得分:1)
我不太懂Python,但可以轻松描述所需的算法:
found <- false
length <- inputString.length
size = 1
output <- inputString
while (not found) and (size <= length / 2) do
if (length % size = 0) then
chunk <- inputString.substring(0, size)
found <- true
for (j <- 1,length/size) do
if (not inputString.substring(j * size, size).equals(chunk)) then
found <- false
if end
for end
if found then
output <- chunk
if end
if end
size <- size + 1
while end
这个想法是越来越多地从字符串的开头开始获取子字符串,子字符串的开始长度为1,并且当您找不到重复的循环时,您增加了长度(直到显然不再可行,是,已达到输入长度的一半)。在每次迭代中,您都将子字符串的长度与输入字符串的长度进行比较,如果输入字符串的长度不能与当前子字符串整除,则当前子字符串对于输入字符串将不会重复(优化将是以找出输入字符串的长度可除以什么数字,并仅检查子字符串中的该长度,但是为了易于理解,我避免了这种优化)。如果字符串的大小可被当前大小整除,则从输入字符串的开始直到当前大小取子字符串,然后检查是否重复。第一次找到这种模式时,就可以停止循环,因为已经找到了解决方案。如果找不到这样的解决方案,则输入字符串是最小的重复子字符串,它会重复0次,因为在您的字符串中只会发现一次。
编辑
如果您想容忍最后一次出现只是模式的一部分,并受inputString的限制,则可以像这样更改算法:
found <- false
length <- inputString.length
size = 1
output <- inputString
while (not found) and (size <= length / 2) do
chunk <- inputString.substring(0, size)
found <- true
for (j <- 1,length/size) do
if (not inputString.substring(j * size, size).equals(chunk)) then
found <- (chunk.indexOf(inputString.substring(j).length) = 0)
if end
for end
if found then
output <- chunk
if end
size <- size + 1
while end
在这种情况下,我们看到的行
found <- (chunk.indexOf(inputString.substring(j).length) = 0)
因此,在不匹配的情况下,我们检查块是否以字符串的其余部分开头。如果是这样,那么我们就在输入字符串的末尾,并且模式会部分匹配直到字符串的末尾,因此发现将为真。如果不是,则发现将为假。
答案 1 :(得分:1)
有效的Z-algorithm
给定一个长度为n的字符串S,Z算法产生一个数组Z 其中Z [i]是从S [i]开始的最长子串的长度 也是S的前缀,即最大k S [j] = S [i + j]对于所有0≤j
计算字符串的Z数组,并找到具有属性i
和i + Z[i] == len
(len % i == 0
是字符串长度)的位置len
。现在i
是周期长度
答案 2 :(得分:0)
您可以这样操作:
def solve(string):
foundPeriods = {}
for x in range(len(string)):
#Tested substring
substring = string[0:len(string)-x]
#Frequency count
occurence_count = string.count(substring)
#Make a comparaison to original string
if substring * occurence_count in string:
foundPeriods[occurence_count] = substring
return foundPeriods[max(foundPeriods.keys())]
for x in cases:
print(x ,'===> ' , solve(x), "#" , len(solve(x)))
print()
输出
abcd ===> a # 1
ababab ===> ab # 2
ababcababc ===> ababc # 5
abcdabcdabc ===> abcd # 4
编辑: 编辑答案以考虑问题中的以下内容
“ abcdabcdabc”,“ abcd”比“ abcdabcdabc”更好,因为它更自然地出现