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

相关推荐
草履虫建模15 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq17 小时前
分布式系统安全通信
开发语言·c++·算法
Jasmine_llq18 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
爱吃rabbit的mq18 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
好家伙VCC19 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
(❁´◡`❁)Jimmy(❁´◡`❁)19 小时前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi19 小时前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
不能隔夜的咖喱20 小时前
牛客网刷题(2)
java·开发语言·算法
VT.馒头20 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
前端玖耀里20 小时前
如何使用python的boto库和SES发送电子邮件?
python