在某些情况下,一个数列被称为“迷人数列”,如果这个数列的最大值和最小值之差不超过某个给定的阈值 k。现在,给定一个由 n 个整数构成的数列和阈值 k,你的任务是统计出数列中有多少个连续的子序列是“迷人的”。
测试样例
样例1:
输入:
n = 4,k = 2,sequence = [3, 1, 2, 4]
输出:8
样例2:
输入:
n = 5,k = 3,sequence = [7, 3, 5, 1, 9]
输出:6
样例3:
输入:
n = 6,k = 1,sequence = [2, 2, 3, 1, 1, 2]
输出:12
def solution(n, k, sequence):
left = 0
result = 0
min_deque = []
max_deque = []
for right in range(n):
# 更新最大值和最小值
while max_deque and sequence[max_deque[-1]] <= sequence[right]:
max_deque.pop()
max_deque.append(right)
while min_deque and sequence[min_deque[-1]] >= sequence[right]:
min_deque.pop()
min_deque.append(right)
# 当窗口不满足条件时,移动左指针
while sequence[max_deque[0]] - sequence[min_deque[0]] > k:
left += 1
if max_deque[0] < left:
max_deque.pop(0)
if min_deque[0] < left:
min_deque.pop(0)
# 当前满足条件的连续子序列数量
result += right - left + 1
return result
if __name__ == "__main__":
# 你可以添加更多测试用例
sequence1 = [3, 1, 2, 4]
sequence2 = [7, 3, 5, 1,9]
sequence3 = [2, 2, 3, 1, 1, 2]
print(solution(4, 2, sequence1) == 8)
print(solution(5, 3, sequence2) == 6)
print(solution(6, 1, sequence3) == 12)
思路分析
-
定义连续子序列:
- 一个连续子序列是数列中从某个起始位置到某个结束位置的所有元素的组合。例如,给定数组
[3, 1, 2, 4],可能的连续子序列包括[3],[1],[2],[4],[3, 1],[1, 2],[2, 4],等等。
- 一个连续子序列是数列中从某个起始位置到某个结束位置的所有元素的组合。例如,给定数组
-
确定迷人的条件:
- 根据题意,迷人的条件是子序列的最大值和最小值之差不超过 kk。因此,我们必须有效的计算每个子序列的最大值和最小值。
-
暴力方法:
- 直接计算每一个可能的子序列,求出其最大值和最小值,然后检查差值是否符合条件。这个方法的时间复杂度是 O(n3)O(n3),因为我们需要 O(n2)O(n2) 次子序列计算,每次计算取最大和最小值又需要遍历 O(n)O(n)。
-
优化 - 使用双指针和单调队列:
- 由于暴力方法效率低,我们可以使用双指针(或称为滑动窗口)技术来优化求解。
- 使用两个指针
left和right来标定当前的子序列范围,初始都指向数组的第一个元素。
具体步骤
-
初始化:
left指针设为 0,result设为 0 用于统计迷人的子序列数量.- 准备两个双端队列
max_deque和min_deque,分别用于维护当前窗口的最大值和最小值的索引。
-
移动右指针:
-
对于每个
right从 0 到 n−1n−1 (即整个数组):- 更新
max_deque:确保队列中的索引对应的值逐渐递减,保持最大值在队列首部。 - 更新
min_deque:确保队列中的索引对应的值逐渐递增,保持最小值在队列首部。
- 更新
-
-
检查迷人的条件:
- 如果
max_deque的最大值和min_deque的最小值之差大于 kk,则需要收缩窗口。 - 移动
left指针,直到子序列满足迷人的条件,同时更新双端队列,移除不在当前窗口的索引。
- 如果
-
计算符合条件的子序列数量:
- 一旦窗口满足条件,我们可以计算以当前
right为结尾的所有符合的子序列数量,即right - left + 1(这是因为对于每个right,left之前的所有位置都是有效的起始位置)。
- 一旦窗口满足条件,我们可以计算以当前
-
继续迭代:
- 重复上述过程直到遍历完所有可能的
right。
- 重复上述过程直到遍历完所有可能的
-
返回结果:
- 最后返回
result,即迷人的子序列的总数。
- 最后返回
时间复杂度
-
使用双指针和双端队列的形式,这种方案能保证整体时间复杂度为 O(n)O(n),因为每个元素的入队和出队操作最多进行一次。
-
HTML(超文本标记语言) :用于定义网页的结构和内容。HTML构成了网页的基础,通过标签来标识各种类型的内容,如段落、图像、链接等。
-
CSS(层叠样式表) :用于控制网页的样式和布局。CSS可以指定元素的颜色、字体、大小、对齐方式,以及响应式设计的布局。它允许开发者以更美观的方式展示信息。
-
JavaScript:用于为网页添加交互性和动态功能。JavaScript 是一种强类型、解释性的编程语言,能够实现网页元素的动态更新,反应用户的操作。此外,与后端进行数据交互也是通过JavaScript(通常使用AJAX或Fetch API)来实现的。
2. 主流技术栈
现代前端开发通常使用一些流行的框架和库来提高开发效率和代码可维护性。以下是一些广泛使用的前端技术栈:
-
框架:
- React:由Facebook开发,基于组件的视图库,允许开发者创建可复用的UI组件,并且通过虚拟DOM提高性能。
- Vue.js:一个渐进式JavaScript框架,易于学习且集成简单,适用于构建复杂的单页应用程序(SPA)。
- Angular:由Google维护的框架,提供全面的解决方案,包括依赖注入、路由、状态管理等,适合大型应用的开发。
-
构建工具:
- Webpack:一个模块打包工具,可以将JS、CSS和其他资源打包成静态文件,支持热更新等特性。
- Babel:一个JavaScript编译器,可以将ES6+代码转换为与旧版本浏览器兼容的语言。
- NPM/Yarn:JavaScript包管理工具,用于安装和管理项目依赖。
3. 设计原则
前端开发不仅限于代码编写,还注重用户体验和设计原则:
- 响应式设计:确保网页在不同设备(手机、平板、桌面)上的良好展示。使用CSS媒体查询根据不同的屏幕尺寸调整布局。
- 可访问性(Accessibility, A11Y) :为所有用户提供良好的体验,包括那些有特殊需求的用户。使用适当的HTML标签、ARIA属性和色彩对比等。
- 用户体验(UX) :关注用户与产品的交互质量。测试用户流程以确定界面的流畅性和易用性,减少用户的认知负荷。
4. 工具和资源
为了提高前端开发的效率,开发者常常使用各种工具和资源:
- 版本控制:使用Git来跟踪代码变化,便于团队协作和版本管理。
- 开发者工具:现代浏览器提供的开发者工具(如Chrome DevTools)用于调试代码、检查样式和分析性能。
- UI设计工具:如Figma和Adobe XD,帮助设计师创建高保真原型,并与开发者协作交付完整的产品。
- 代码编辑器:如Visual Studio Code、Sublime Text等,提供高效的代码编辑体验,支持插件扩展和调试工具。