豆包MarsCode AI刷题记录——学习方法与心得
问题描述
小U拿到了一组排列,她想知道有多少个子区间满足区间内部的数构成一个排列。一个区间的排列是指:该区间的数包含从 11 到 kk 的每个数,并且每个数恰好出现一次,这个区间的长度为 kk。
例如,对于数组 [2, 1, 5, 3, 4],其中区间 [2, 2],[1,2] 和 [1, 5] 都是排列。
题目解析
这个问题要求我们找到数组中所有长度为 k 的子区间,这些子区间内的元素构成从 1 到 k 的一个排列。排列是指每个数字恰好出现一次。
理解排列:一个长度为 k 的子数组是排列,当且仅当它包含从 1 到 k 的所有整数,每个整数恰好出现一次。
遍历所有子区间:为了找到所有满足条件的子区间,我们需要遍历数组中所有可能的子区间。这可以通过两个嵌套的循环实现,外层循环固定子区间的起始位置,内层循环固定子区间的结束位置。
检查子区间是否为排列:对于每个子区间,我们需要检查它是否是排列。检查的方法是看子区间内的元素集合是否等于从 1 到 k 的整数集合。我们可以通过将子区间的元素转换成集合,然后与包含 1 到 k 的整数集合进行比较来实现。
计数:每当找到一个符合条件的子区间,我们就增加计数器的值。
具体步骤如下:
- 初始化一个计数器
count为 0。 - 使用两个嵌套循环,外层循环变量
i表示子区间的起始位置,内层循环变量j表示子区间的结束位置。 - 在内层循环中,检查子区间
a[i:j+1]是否是排列。如果是,则将count加 1。 - 最后返回
count的值。
代码中,is_permutation 函数负责检查一个子区间是否是排列。它首先获取子区间的长度 k,然后比较子区间的元素集合与从 1 到 k 的整数集合是否相等。
在主函数 solution 中,我们遍历所有可能的子区间,并使用 is_permutation 函数检查每个子区间。如果子区间是排列,我们就增加计数器的值。
代码详解
def solution(n: int, a: list) -> int:
def is_permutation(subarray):
k = len(subarray)
if k == 0:
return False
num_set = set(subarray)
return num_set == set(range(1, k + 1))
count = 0
for i in range(n):
for j in range(i, n):
if is_permutation(a[i:j+1]):
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 到某个数 k 的所有整数。
-
哈希表(字典) :
- 哈希表是一种数据结构,可以存储键值对,并且提供快速的查找、插入和删除操作。
- 在这个问题中,我们使用哈希表来记录窗口内每个元素的出现次数。
-
滑动窗口:
- 滑动窗口是一种常用的算法技巧,用于处理数组或字符串中的连续子结构问题。
- 通过两个指针(通常称为左右指针)来表示窗口的边界,并随着指针的移动来动态调整窗口的大小。
-
双指针技术:
- 双指针技术是指使用两个指针在数组或字符串中移动,以解决问题的一种方法。
- 在滑动窗口中,一个指针用于扩展窗口,另一个指针用于收缩窗口。
-
集合操作:
- 集合操作包括并集、交集、差集等,可以用来快速判断两个集合是否相等。
-
算法优化:
- 在解决算法问题时,寻找更高效的解决方案是关键。
- 从暴力解法到滑动窗口的优化,可以显著提高算法的效率。
-
边界条件处理:
- 在编写算法时,需要特别注意边界条件,如数组的起始和结束位置,以及窗口大小的调整。
复杂度分析
上面给出的方法的时间复杂度是 O(n^2),因为对于每个可能的 k 值,我们使用滑动窗口遍历整个数组一次。对于大多数情况,这个方法比暴力解法更高效。
AI刷题与python学习经验
分享一个补充基础语法的python学习网站,结合着豆包MarsCode AI刷题用很有效,感觉比啃书效率高一些。用AI刷题的话方便之处就是还能帮忙检查错误,其实一些可以避免的错误或者是机械性地工作交给AI去做挺好的,解放大脑去做更多创造性的工作。但是AI始终是工具,我们自己还是要学习,以便保持清醒的判断力。