最小循环子数组 Python

 难度指数:⭐⭐⭐⭐

知识点:KMP

通用一般算法:

2023华为od机试【最小循环子数组】Python

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值