[英]determine if list is periodic python
我很想找到一个函数来检查给定的列表是否是周期性的并返回周期性元素。 列表不会被加载,而是它们的元素是动态生成和添加的,如果这个注释无论如何会使算法更容易。
例如,如果函数的输入为[1,2,1,2,1,2,1,2]
,则输出应为 (1,2)。
我正在寻找有关实现此目标的更简单方法的一些提示和提示。
提前致谢,
这个问题可以通过用于字符串匹配的Knuth-Morris-Pratt算法来解决。 在继续之前,请熟悉计算故障链接的方式。
让我们将列表视为类似于值序列(如字符串)的东西。 让列表/序列的大小为n
。
然后你可以:
找到列表中最长的适当前缀的长度,它也是一个后缀。 让最长的适当前缀后缀的长度为len
。
如果n
可被n - len
整除,则该列表是周期性的且周期大小为len
。 在这种情况下,您可以打印第一个len
值。
更多信息:
注意:原始问题有python
和python-3.x
标签,它们不是由 OP 编辑的,这就是为什么我的答案是在 python 中的。
我使用itertools.cycle
和zip
来确定列表对于给定的 k 是否是 k 周期的,然后只需迭代所有可能的 k 值(最多为列表长度的一半)。
尝试这个:
from itertools import cycle
def is_k_periodic(lst, k):
if len(lst) < k // 2: # we want the returned part to repaet at least twice... otherwise every list is periodic (1 period of its full self)
return False
return all(x == y for x, y in zip(lst, cycle(lst[:k])))
def is_periodic(lst):
for k in range(1, (len(lst) // 2) + 1):
if is_k_periodic(lst, k):
return tuple(lst[:k])
return None
print(is_periodic([1, 2, 1, 2, 1, 2, 1, 2]))
输出:
(1, 2)
谢谢大家回答我的问题。 尽管如此,我想出了一个适合我需求的实现。
我将在这里与您分享,期待您的投入以优化它以获得更好的性能。
算法是:
- 假设输入列表是周期性的。
- 初始化模式列表。
- 对于前半部分的每个元素i ,将列表翻到一半:
- 将元素添加到模式列表中。
- 检查模式是否在整个列表中匹配。
- 如果匹配,则声明成功并返回模式列表。
- 否则中断并再次开始循环,将下一个元素添加到模式列表中。
- 如果找到模式列表,则检查列表的最后k 个元素,其中k是len(list) - len(list) 以模式列表的长度为模,如果是,则返回模式列表,否则声明失败。
python
的代码:
def check_pattern(nums):
p = []
i = 0
pattern = True
while i < len(nums)//2:
p.append(nums[i])
for j in range(0, len(nums)-(len(nums) % len(p)), len(p)):
if nums[j:j+len(p)] != p:
pattern = False
break
else:
pattern = True
# print(nums[-(len(nums) % len(p)):], p[:(len(nums) % len(p))])
if pattern and nums[-(len(nums) % len(p)) if (len(nums) % len(p)) > 0 else -len(p):] ==\
p[:(len(nums) % len(p)) if (len(nums) % len(p)) > 0 else len(p)]:
return p
i += 1
return 0
该算法在性能方面可能效率低下,但即使最后一个元素没有形成完整的周期,它也会检查列表。
任何提示或建议都非常感谢。
提前致谢,,,
让L
列出来。 经典方法是:使用您喜欢的算法在列表L+L
搜索子列表L
的第二次出现。 如果列表位于索引k
,则周期为L[:k]
:
L L
1 2 1 2 1 2 1 2 | 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2
(这在概念上与@KonstantinYovkov 的回答相同)。 在 Python 中:带有字符串的示例(因为 Python 没有内置的子列表搜索方法):
>>> L = "12121212"
>>> k = (L+L).find(L, 1) # skip the first occurrence
>>> L[:k]
'12'
但:
>>> L = "12121"
>>> k = (L+L).find(L, 1)
>>> L[:k] # k is None => return the whole list
'12121'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.