难度指数:⭐⭐⭐⭐
知识点:KMP
通用一般算法:
def solve():
target = []
kmp_arr = [-1 for i in range(n+1)]
i = 0
j = -1
while (True):
if i >= len(nums):
break;
if j == -1 or nums[i] == nums[j]:
i += 1
j += 1
kmp_arr[i] = j
else:
j = kmp_arr[j]
m = 0
while(True):
if(m>=len(nums) - kmp_arr[len(nums)]):
break
target.append(nums[m])
m+=1
return target
创新算法
idea
- 最小循环子数组可以由出现次数最少的元素进行标识;
- 子数组的个数 = 出现的总次数m / 单个子数组中出现的次数k
- 子数组的长度 = 总数组长度 / 子数组个数
- 子数组长度 = k * 总数组长度n / 出现的总次数m
代码实现
def solve0():
nums0 = list(set(nums))
c = []
for i in nums0:
c.append(nums.count(i))
m = min(c)
k = 1
while 2 * k <= m:
if m % k == 0 and n * k % m == 0:
km = m // k
kl = n * k // m
num = nums[:kl]
for i in range(1, km):
if nums[i * kl:(i + 1) * kl] != num:
k += 1
break
elif i == km-1:
return num
else:
k += 1
return nums
对比验证
耗时对比:
from time import time
import random
def solve():
target = []
kmp_arr = [-1 for i in range(n+1)]
i = 0
j = -1
while (True):
if i >= len(nums):
break;
if j == -1 or nums[i] == nums[j]:
i += 1
j += 1
kmp_arr[i] = j
else:
j = kmp_arr[j]
m = 0
while(True):
if(m>=len(nums) - kmp_arr[len(nums)]):
break
target.append(nums[m])
m+=1
return target
def solve0():
nums0 = list(set(nums))
c = []
for i in nums0:
c.append(nums.count(i))
m = min(c)
k = 1
while 2 * k <= m:
if m % k == 0 and n * k % m == 0:
km = m // k
kl = n * k // m
num = nums[:kl]
for i in range(1, km):
if nums[i * kl:(i + 1) * kl] != num:
k += 1
break
elif i == km-1:
return num
else:
k += 1
return nums
T = 10
while T:
mm = random.randint(1, 1e2)
mn = random.randint(1, 500)
n = mn * mm
nums = [random.randint(0, 10) for _ in range(mn)] * mm
t1 = time()
res = solve()
t2 = time()
res0 = solve0()
t3 = time()
if res != res0:
print(len(res), len(res0), mn, mm)
if 0:
print(' '.join(list(map(str, res))))
print(' '.join(list(map(str, res0))))
print(t2 - t1, t3 - t2)
T -= 1