最新华为OD机试
题目描述
给定一个由若干整数组成的数组nums,请检查数组是否是由某个子数组重复循环拼接而成,请输出这个最小的子数组。
输入描述
第一行输入数组中元素个数n,1 ≤ n ≤ 100000
第二行输入数组的数字序列nums,以空格分割,0 ≤ nums[i] < 10
备注
数组本身是其最大的子数组,循环1次可生成的自身;
输出描述
输出最小的子数组的数字序列,以空格分割;
示例1
输入
9
1 2 1 1 2 1 1 2 1
输出
1 2 1
说明
数组[1,2,1,1,2,1,1,2,1] 可由子数组[1,2,1]重复循环3次拼接而成
解题思路
问题理解
这道题要求我们找到一个最小的子数组,该子数组通过循环拼接可以构成原始数组。例如,对于数组 [1,2,1,1,2,1,1,2,1]
,最小的循环子数组是 [1,2,1]
,它重复3次可以生成原数组。
算法原理
这个问题可以使用 KMP 算法的思想来解决。KMP 算法主要用于字符串匹配,但其中的"前缀函数"(next数组)可以帮助我们找到循环模式。
KMP 的 next 数组在这里的应用
- next数组记录了每个位置的最长相等前后缀长度
- 对于数组末尾位置 i,next[i] 表示数组的前 next[i] 个元素与末尾的 next[i] 个元素相同
- 如果数组是由某个子数组循环构成的,那么 (数组长度 - next[末尾位置]) 就是可能的循环子数组的长度
关键思路
如果一个数组是循环构成的,假设循环子数组长度为 k,数组长度为 n,则有:
- n 必须是 k 的整数倍
- 如果 (n % (n - next[n-1]) == 0),说明数组可以被分成整数个循环子数组
- 此时最小循环子数组长度为 (n - next[n-1])
- 否则,无法找到真正的循环子数组,整个数组本身就是最小的"循环子数组"(循环1次)
示例分析
对于输入 [1,2,1,1,2,1,1,2,1]
:
- 构建 next 数组:[0,0,1,1,2,3,4,5,6]
- 最后一个元素的 next 值是 6
- 计算:9 % (9 - 6) = 9 % 3 = 0,可以整除
- 因此最小循环子数组长度为 3
- 输出前 3 个元素:[1,2,1]
Java
import java