问题描述
小U拿到了一组排列,她想知道有多少个子区间满足区间内部的数构成一个排列。一个区间的排列是指:该区间的数包含从 1 到 k 的每个数,并且每个数恰好出现一次,这个区间的长度为 k。
例如,对于数组 [2, 1, 5, 3, 4],其中区间 [2, 1],[5, 3, 4] 和 [1, 5, 3, 4] 都是排列。
测试样例
样例1:
输入:
n = 5 ,a = [2, 1, 5, 3, 4]
输出:3
样例2:
输入:
n = 5 ,a = [1, 2, 3, 4, 5]
输出:5
样例3:
输入:
n = 4 ,a = [4, 3, 2, 1]
输出:4
思路解析
暴力枚举所有区间
通过枚举所有可能的子区间起点和终点,判断其是否构成一个排列:
-
遍历区间起点 start,枚举从起点到数组末尾的所有子区间。
-
使用集合 seen 记录子区间内的所有数,确保没有重复元素。
-
判断:
- 区间长度 length 等于集合的大小(无重复元素)。
- 集合中的最大值等于当前区间的长度(包含 1 到 k 的所有整数)。
优化剪枝
- 如果当前区间长度大于集合的大小,说明有重复元素,后续区间不可能构成排列,可直接结束当前起点的检查。
复杂度分析
- 时间复杂度:
外层起点遍历 O(n),内层终点遍历 O(n),总体为 O(n^2)。 - 空间复杂度:
使用集合存储子区间的元素,空间复杂度为 O(k),其中 k 为最大区间长度。
Python 实现
def solution(n: int, a: list) -> int:
count = 0
# 遍历所有可能的起点
for start in range(n):
seen = set()
# 遍历从当前起点开始的子区间
for end in range(start, n):
seen.add(a[end])
length = end - start + 1
# 检查当前区间是否包含完整的 1 到 k
if length > len(seen):
break # 区间有重复元素,剪枝
if length == len(seen) and length == max(seen):
count += 1 # 当前区间是排列
return count
if __name__ == '__main__':
print(solution(5, [2, 1, 5, 3, 4]) == 3)
print(solution(5, [1, 2, 3, 4, 5]) == 5)
print(solution(4, [4, 3, 2, 1]) == 4)
测试样例解析
样例 1:
输入:n=5,a=[2,1,5,3,4]n = 5, a = [2, 1, 5, 3, 4]n=5,a=[2,1,5,3,4]
过程:
- 子区间 [2,1][2, 1][2,1]:长度 2,包含 1, 2(有效)。
- 子区间 [5,3,4][5, 3, 4][5,3,4]:长度 3,包含 3, 4, 5(有效)。
- 子区间 [1,5,3,4][1, 5, 3, 4][1,5,3,4]:长度 4,包含 1, 3, 4, 5(有效)。
结果:3
样例 2:
输入:n=5,a=[1,2,3,4,5]n = 5, a = [1, 2, 3, 4, 5]n=5,a=[1,2,3,4,5]
过程:所有区间均为排列,结果为 5。
样例 3:
输入:n=4,a=[4,3,2,1]n = 4, a = [4, 3, 2, 1]n=4,a=[4,3,2,1]
过程:每个区间都是排列,结果为 4。
总结
该方法通过暴力枚举并结合剪枝优化,有效计算数组中满足条件的排列区间数,适用于数组规模较小的场景。