【精品】【算法实战】每日一题:如何用Python实现给定整数序列中寻找最小长度窗口以包含所有不同元素的算法?

问题:

如何用Python实现给定整数序列中寻找最小长度窗口以包含所有不同元素的算法?

核心思路

核心思路是利用双端队列(作为滑动窗口)来找到一个满足特定条件的最小长度子序列。算法遍历给定的序列,对于每个新数据点,执行以下三种操作之一:

  1. 如果数据点不在当前窗口中,则将其添加到队列中(表示窗口扩展)。
  2. 如果数据点已存在于窗口中,但队首和队尾的元素不同(意味着窗口中尚需包含此元素),则仍然将其加入队列。(损耗元素,知道有但是还是得加入)
  3. 如果数据点已存在,且队首和队尾的元素相同(表示该元素类型已满足),则从队列中移除队首元素(缩短窗口)。

在遍历过程中,维护一个记录最小长度窗口的变量。如果当前窗口包含所有必需的不同元素类型,并且比之前记录的任何窗口都小,则更新最小长度窗口的记录。最终,得到一个满足条件的最小长度窗口。

进一步给出伪码思路

复制代码
初始化一个双端队列 q 和一些计数器以及变量。

定义主函数 main:
    读取输入的 n 和 m,分别代表数组长度和目标不同元素的数量。
    读取数组 a 并将其转换为整数列表。
    对数组 a 中的每个元素执行以下操作:
        如果当前元素的计数器 cnt 为 0,增加类型数量 type。
        增加当前元素的计数器。
        将当前索引添加到双端队列 q 的末尾。
        如果双端队列 q 不为空且队首元素的计数器大于 1,移除队首元素,直到计数器为 1。
        如果当前类型数量等于目标 m 且双端队列的长度小于当前记录的最小长度 ans,则更新 ans 以及起始索引 l 和结束索引 r。
    打印出最小长度窗口的起始索引和结束索引,索引加 1(因为 Python 索引从 0 开始)。

定义函数 qsize 来返回双端队列 q 的大小。

如果这是主程序,调用 main 函数。

CODE

python 复制代码
from collections import deque

# 初始化变量
ans = float('inf')
n, m = 0, 0
a = []
cnt = [0] * 10000
l, r, type = 0, 0, 0
q = deque()

def main():
    global ans, l, r, type
    n, m = map(int, input().split())
    a = list(map(int, input().split()))
    
    # 统计每个数出现的次数,并判断是否需要type++
    for i in range(n):
        if cnt[a[i]] == 0:
            type += 1
        cnt[a[i]] += 1
        q.append(i)
        
        # 移除队首元素,直到cnt[a[q[0]]]为0
        while q and cnt[a[q[0]]] > 1:
            cnt[a[q.popleft()]] -= 1
            
        # 如果type=m,且队列长度<ans,则更新ans和l,r
        if type == m and qsize() < ans:
            ans = qsize()
            l = q[0]
            r = q[-1]
    
    print(l + 1, r + 1)  # 输出时加1,因为Python索引从0开始

def qsize():
    return len(q)

if __name__ == '__main__':
    main()

注:

  1. ans = float('inf'):
    ans 变量用于存储找到的满足条件的最小长度子数组的长度。初始化为正无穷大(float('inf')),意味着我们从找一个非常大的长度开始,随着算法的进行,如果找到更小的满足条件的子数组,就会更新这个值。

  2. n, m = 0, 0:
    n 是数组 a 的长度,即数组中元素的总数。
    m 是我们需要在子数组中找到的不同元素的类型数。

  3. a = []:
    a 是一个空列表,稍后将用来存储输入的整数数组。

  4. cnt = [0] * 10000:
    cnt 是一个长度为 3000 的列表,用于计数。它将用于跟踪数组 a 中每个元素的出现次数,10000因为测试用例可能比较大

  5. l, r, type = 0, 0, 0:
    lr 是子数组的起始和结束索引,初始化为 0。随着算法的进行,它们将被更新为满足条件的最小长度子数组的起始和结束索引。
    type 是一个计数器,用于跟踪当前窗口中不同元素的类型数。

  6. q = deque():
    q 是一个 deque(双端队列)实例,它将被用作滑动窗口的数据结构。双端队列允许我们从两端快速添加和删除元素,非常适合实现滑动窗口。

END

相关推荐
亿牛云爬虫专家2 分钟前
微服务化采集平台:可扩展性与容错机制
python·微服务·架构·爬虫代理·扩展性·新浪财经·财经新闻
傻啦嘿哟18 分钟前
Python爬虫动态IP代理报错全解析:从问题定位到实战优化
爬虫·python·tcp/ip
mit6.82420 分钟前
[Meetily后端框架] Whisper转录服务器 | 后端服务管理脚本
c++·人工智能·后端·python
zhangfeng113321 分钟前
python 数据分析 单细胞测序数据分析 相关的图表,常见于肿瘤免疫微环境、细胞亚群功能研究 ,各图表类型及逻辑关系如下
开发语言·python·数据分析·医学
柠檬豆腐脑40 分钟前
Trae-Agent 内置工具深度解析
python·llm·agent
ydl11281 小时前
机器学习基础知识【 激活函数、损失函数、优化器、 正则化、调度器、指标函数】
python·机器学习
我爱C编程2 小时前
基于Qlearning强化学习的1DoF机械臂运动控制系统matlab仿真
算法
chao_7892 小时前
CSS表达式——下篇【selenium】
css·python·selenium·算法
chao_7892 小时前
Selenium 自动化实战技巧【selenium】
自动化测试·selenium·算法·自动化
YuTaoShao2 小时前
【LeetCode 热题 100】24. 两两交换链表中的节点——(解法一)迭代+哨兵
java·算法·leetcode·链表