一、滑动窗口
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
,如果可以翻转最多 k
个 0
,则返回 数组中连续 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())