常见算法总结:滑动窗口+哈希表

一、滑动窗口

3. 无重复字符的最长子串(mid)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

# 限制窗口:无重复字符
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:  # 当输入字符串s为空字符串时,直接返回0
            return 0
        left = 0
        target = list()
        cur_len = 0
        max_len = 0
        for right in range(len(s)):
            cur_len += 1
            while s[right] in target:  # 若有重复字符,则左指针前移
                target.remove(s[left])
                left += 1
                cur_len -= 1
            if cur_len > max_len: # 更新最长子串长度
                max_len = cur_len
            target.append(s[right])
        return max_len

1423. 可获得的最大点数(mid)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

# 窗口长度固定
class Solution:
    def maxScore(self, cardPoints: List[int], k: int) -> int:
        if k <= 0 or k > len(cardPoints):
            return
        left = 0
        lenth = len(cardPoints) - k        # lenth表示滑动窗口大小
        min_sum = sum(cardPoints[:lenth])  # 选前lenth个作为初始值
        cur_sum = sum(cardPoints[:lenth])
        for right in range(lenth, len(cardPoints)):
            cur_sum += cardPoints[right]
            cur_sum -= cardPoints[left]
            left += 1
            min_sum = min(min_sum, cur_sum)
        return sum(cardPoints) - min_sum

1004. 最大连续1的个数 III(mid)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k0 ,则返回 数组中连续 1 的最大个数


# 限制窗口:最多k个0
class Solution:
    def longestOnes(self, nums: List[int], k: int) -> int:
        zero_num = 0
        cur_len = 0
        max_len = 0
        left = 0
        for right in range(len(nums)):
            if nums[right] == 0:
                zero_num += 1
            if zero_num > k:  # 如果窗口内0的个数大于k,则左指针前移直到移出一个0
                while nums[left] != 0:
                    left += 1
                    cur_len -= 1
                left += 1
                cur_len -= 1
                zero_num -= 1
            cur_len += 1
            max_len = max(max_len, cur_len)
        return max_len

1438. 绝对差不超过限制的最长连续子数组(mid)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit

如果不存在满足条件的子数组,则返回 0

# 限制窗口:任意元素的绝对差≤limit
class Solution:
    def longestSubarray(self, nums: List[int], limit: int) -> int:
        left = 0
        cur_len = 0
        max_len = 0
        target = list()
        for right in range(len(nums)):
            cur_len += 1
            target.append(nums[right])
            target.sort()
            while target[len(target)-1] - target[0] > limit:
                target.remove(nums[left])
                left += 1
                cur_len -= 1
            max_len = max(max_len, cur_len)
        return max_len
# 用特殊数据类型SortedList(插入元素时自动保持有序),用add插入,用remove删除
from sortedcontainers import SortedList
class Solution:
    def longestSubarray(self, nums: List[int], limit: int) -> int:
        s = SortedList()
        n = len(nums)
        left = right = ret = 0

        while right < n:
            s.add(nums[right])
            while s[-1] - s[0] > limit:
                s.remove(nums[left])
                left += 1
            ret = max(ret, right - left + 1)
            right += 1
        
        return ret

76. 最小覆盖子串(hard)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

# 限制窗口:涵盖t中所有字符
class Solution:
    def minWindow(self, s: str, t: str) -> str:

        target = {}  # 统计字符串 t 中每个字符出现的次数
        for char in t:
            if char in target:
                target[char] += 1
            else:
                target[char] = 1

        left, right = 0, 0      # 窗口的左右边界
        window = {}             # 统计窗口中每个字符出现的次数

        t_type = len(target)    # t中的字符种类数
        w_type = 0              # 窗口中的字符种类数

        ans = ""                # s 中涵盖 t 所有字符的最小子串
        min_len = float('inf')  # 最小子串的长度

        while right < len(s):
            
            # 右边界右移时更新各信息
            char = s[right]  
            if char in window:
                window[char] += 1
            else:
                window[char] = 1
            if char in target and window[char] == target[char]:
                w_type += 1

            # 满足条件时尝试右移左边界
            while left <= right and w_type == t_type:

                if right - left + 1 < min_len:  # 更新最小子串
                    min_len = right - left + 1
                    ans = s[left:right + 1]

                char = s[left]  # 左边界右移直到不满足条件
                window[char] -= 1
                left += 1
                if char in target and window[char] < target[char]:
                    w_type -= 1

            right += 1

        return ans

二、哈希表

49. 字母异位词分组(mid)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        table = {}
        for s in strs:
            sorted_s = "".join(sorted(s))   # 获得字符串 s 排序后的字符串表示
            if sorted_s not in table:
                table[sorted_s] = [s]
            else:
                table[sorted_s].append(s)
        return list(table.values())
  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值