1. 解题思路
当出现求连续子串最大/最小,最大/最小子区间之类的题目时,一般采用滑动窗口进行求解。对滑动窗口不了解可以先参考此篇文章。
可以按照以下思路进行思考:
- 1、什么时候应该扩大窗口? 窗口扩大时应该做什么
- 2、什么时候应该缩小窗口? 窗口缩小时应该做什么
- 3、什么时候得到一个合法的答案?(求最大是在窗口扩大时更新值,求最小是在窗口缩小时更新值。)
2. 代码
class Solution:
def characterReplacement(self, s: str, k: int) -> int:
left = 0
right = 0
n = len(s)
s_dict = dict()
ans = 1
while (right < n):
s_dict[s[right]] = s_dict.get(s[right], 0) + 1
# 除最多字符外,其他字符出现的次数不能超过k次
while (right - left + 1) - max(s_dict.values()) > k:
# 先减去最左边的值
s_dict[s[left]] -= 1
left += 1
# 先更新ans
ans = max(ans, right - left + 1)
right += 1
return ans
3. LeetCode其他滑动窗口的题
3. 无重复字符的最长子串
自己写的通过的代码:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
left = 0
right = 0
n = len(s)
cur_s = ""
ans = 1
while (right < n):
cur_s += s[right]
# 这块当时没想通,缩小窗口的条件为出现重复的子串
while len(cur_s) != len(set(cur_s)):
cur_s = s[left + 1:right + 1]
left += 1
ans = max(ans, right - left + 1)
right += 1
return ans
1052. 爱生气的书店老板
此题为固定长度的滑动窗口
class Solution:
"""
固定大小的滑动窗口
参考链接:https://leetcode.cn/problems/grumpy-bookstore-owner/solution/hua-dong-chuang-kou-luo-ti-by-ac_oier-nunu/
思路:先计算本来可以留下的顾客,计算时将本来可以留下的顾客的customers[i]置为0。之后找出在minutes时间内最大的customers子数组和,最后计算答案
"""
def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int:
n = len(customers)
ans = 0
for i in range(n):
if grumpy[i] == 0:
ans += customers[i]
customers[i] = 0
minutes_ans = 0
for i in range(n):
# i + minutes - 1要取到n-1,但不能大于n-1
if i + minutes > n:
break
minutes_ans = max(minutes_ans, sum(customers[i:i + minutes]))
return ans + minutes_ans
209. 长度最小的子数组
此题求最小值
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
left = 0
right = 0
n = len(nums)
cur_sum = 0
ans = n
while right < n:
cur_sum += nums[right]
while cur_sum >= target:
# 最小值在窗口缩小时更新
ans = min(ans, right - left +1)
cur_sum -= nums[left]
left += 1
right += 1
if target > sum(nums):
return 0
return ans
1156. 单字符重复子串的最大长度
1156. 单字符重复子串的最大长度
此题不能直接套用模板,参考官方解答
class Solution:
def maxRepOpt1(self, text: str) -> int:
count = collections.Counter(text)
res = 0
for i in range(len(text)):
# step1: 找出当前连续的一段 [i, j)
j = i
while j < len(text) and text[j] == text[i]:
j += 1
# step2: 如果这一段长度小于该字符出现的总数,并且前面或后面有空位,则使用 cur_cnt + 1 更新答案
cur_cnt = j - i
if cur_cnt < count[text[i]] and (j < len(text) or i > 0):
res = max(res, cur_cnt + 1)
# step3: 找到这一段后面与之相隔一个不同字符的另一段 [j + 1, k),如果不存在则 k = j + 1
k = j + 1
while k < len(text) and text[k] == text[i]:
k += 1
res = max(res, min(k - i, count[text[i]]))
i = j
return res