[英]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.