hot100-子串

560. 和为k的子数组

560. 和为 K 的子数组 - 力扣(LeetCode)

python 复制代码
class Solution(object):
    def subarraySum(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 求的是连续子串,所以排序不可以用
        # 又数字有正有负,所以快慢指针会失效!
        # 使用前缀和的思想,如果有一个子串j~i相加为k,则i的前缀和减去(j-1)的前缀和等于k
        d = {0:1}  # j=0,j-1=-1,我们定义一个0的前缀和
        pre = 0
        res = 0
        for i in range(len(nums)):
            pre += nums[i]  # i的前缀和
            res += d.get(pre-k,0)
            d[pre] = d.get(pre,0) + 1
        return res

时间复杂度:O(N)

空间复杂度:O(N)

239. 滑动窗口最大值

239. 滑动窗口最大值 - 力扣(LeetCode)

题目看起来很简单,但是我们如果在每个子数组中都去统计最大值,那么时间复杂度就会很高O(kN),最终会超时!

那么遍历数组的O(N)是不可少的,我们希望让获取max的操作变成O(1);假如我们仅仅是每遍历一个数组,仅仅记录最大值,但是我们就不知道这个最大值什么时候从当前窗口弹出!

最终实现使用的是单调队列!【这里单调队列更加适合,因为在滑动窗口的移动中,先进入的先弹出!】

python 复制代码
class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        dq = []
        for i in range(k):
            # 单调队列:队首元素最大!
            # 其实我们不在乎队列里面到底存多少个元素,我们仅仅是留下较大的元素的下标
            # 如果新入队的元素下标和队首差距只要不超过k,那么当前的队首就还是最大元素
            # 如何保证单调性呢?从队尾开始比,比如7 3 5如果仅仅和队首比,就会有问题,中间那些小的依然在
            # 我们要保证的单调性就是队首到队尾的单调递减
            while dq and nums[i]>nums[dq[-1]]:
                dq.pop()  # 比的是队尾,弹的是队尾
            dq.append(i)
        res.append(nums[dq[0]])
        for i in range(k,len(nums)):
            while dq and nums[i]>nums[dq[-1]]:
                dq.pop()
            dq.append(i)
            while i-dq[0]>=k:
                dq.pop(0)  # 距离过大弹队首
            res.append(nums[dq[0]])
        return res
操作 Python list collections.deque 说明
append() 尾部入队 O(1) O(1) 两者都高效
pop() 尾部出队 O(1) O(1) 两者都高效
pop(0) 头部出队 O(n) O(1) 列表需要移动元素
insert(0, item) 头部入队 O(n) O(1) 列表需要移动元素
随机访问 queue[i] O(1) O(n) deque随机访问慢
python 复制代码
class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        dq = collections.deque()
        for i in range(k):
            while dq and nums[i]>nums[dq[-1]]:
                dq.pop()  # 比的是队尾,弹的是队尾
            dq.append(i)
        res.append(nums[dq[0]])
        for i in range(k,len(nums)):
            while dq and nums[i]>nums[dq[-1]]:
                dq.pop()
            dq.append(i)
            while i-dq[0]>=k:
                dq.popleft()  # 距离过大弹队首
            res.append(nums[dq[0]])
        return res

但是如果是栈的话,用list差不多!【查看栈顶或者弹出栈顶,都是对列表最后一个元素操作,时间复杂度差不多!】

时间复杂度:O(N) 【每个元素除被遍历外,最多入对一次,出队一次 最多3N】

空间复杂度:O(k) 【队列的最大长度就是k】

76. 最小覆盖子串

76. 最小覆盖子串 - 力扣(LeetCode)

python 复制代码
class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        m = len(s)
        n = len(t)
        if not s or not t or m<n:
            return ""
        dt = collections.Counter(t)
        ds = collections.Counter()
        min_len = m+1
        min_left = left = 0
        required = len(dt)
        cur = 0  # 记录一下有多少满足了
        for right in range(m):
            char = s[right]
            ds[char] += 1
            if char in dt and ds[char] == dt[char]:
                cur += 1
            # 既然找到了一个子串,我们其实可以尽可能的缩小左边界【注意,并非直接判断】
            # 比如最开始的几个字符可能都是其他字符,我们要while 缩小
            while left<=right and cur == required:
                win_len = right-left+1
                if win_len<min_len:
                    min_len = win_len
                    min_left = left
                left_char = s[left]
                ds[left_char] -= 1
                # 这里除了比较在不在,还需要比较大小,因为在之前的代码中,我们一旦满足某一个字符,但是之后可能会继续增加该字符
                if left_char in dt and ds[left_char] < dt[left_char]:
                    cur -=1
                left += 1
        return "" if min_len == m+1 else s[min_left:min_left+min_len]

时间复杂度:O(N) 最多相当于left和right两遍遍历!

空间复杂度:O(N) 两个字典

相关推荐
2601_962078191 小时前
Python中calendar.weekday用法
python·编程技巧·calendar·日期处理·weekday
2601_962218611 小时前
万象生鲜系统业财一体化底层打通技术自动生成经营账单
大数据·数据库·人工智能·python·算法
2601_966949651 小时前
为什么量化策略需要大量历史股票数据?从回测可信度理解数据规模
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
2601_962885721 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
吞下星星的少年·-·1 小时前
The 2026 ICPC Asia East Continent Online Contest (II)(构造)
数据结构·算法
李高钢2 小时前
Python FastAPI 框架入门:从零搭建你的第一个高性能 API 服务
数据库·python·fastapi
ocean21032 小时前
2025-2026年Python面试高频知识点洞察
开发语言·python·面试·python八股文
Warson_L2 小时前
Python的OrderedDict
python
stolentime2 小时前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
隐擎fox2 小时前
高性能网络爬虫架构设计:基于 Python 的长连接复用与分布式会话池调度实践
分布式·python·网络协议·tcp/ip·高并发·网络爬虫、