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) 两个字典

相关推荐
白白白小纯几秒前
算法篇—反转链表
c语言·数据结构·算法·leetcode
Achou.Wang15 分钟前
深入理解go语言-第5章 并发编程——Go的灵魂
大数据·算法·golang
The Chosen One98523 分钟前
高进度算法模板速记(待完善)
java·前端·算法
Gu Gu Study27 分钟前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境1 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境1 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1231 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102162 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb002 小时前
一个项目带你入门AI应用开发01
python
0566463 小时前
Python康复训练——常用标准库
开发语言·python·学习