技术标签: 算法 python 笔记 Leetcode刷题笔记 leetcode
链表子串数组题,用双指针别犹豫。
双指针家三兄弟,各个都是万人迷。
快慢指针最神奇,链表操作无压力。
归并排序找中点,链表成环搞判定。
左右指针最常见,左右两端相向行。
反转数组要靠它,二分搜索是弟弟。
滑动窗口老猛男,子串问题全靠它
左右指针滑窗口,一前一后齐头进
自诩十年老司机,怎料农村道路滑。
一不小心滑到了,鼻青脸肿少颗牙。
算法思想很简单,出了bug想升天
Leetcode485:最大连续1的个数:简单题 (详情点击链接见原题)
给定一个二进制数组
nums
, 计算其中最大连续1
的个数
python代码解法:
class Solution:
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
left, right, res = 0, 0, 0
while right < len(nums):
if nums[right] == 1:
right += 1
else:
left = right # 左指针和右指针指向同一个位置
left += 1
right += 1
res = max(res, right - left)
return res
Leetcode643:子数组的最大平均数I:简单题 (详情点击链接见原题)
给你一个由
n
个元素组成的整数数组nums
和一个整数k
。
请你找出平均数最大且 长度为k
的连续子数组,并输出该最大平均数。
python代码解法:
class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
left, right = 0, 0
slide_total = 0
max_average = -float('inf')
while right < len(nums):
slide_total += nums[right]
right += 1
while right - left >= k:
max_average = max(max_average, slide_total / k)
slide_total = slide_total - nums[left]
left += 1
return max_average
Leetcode594. 最长和谐子序列:简单题 (详情点击链接见原题)
和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是
1
。
现在,给你一个整数数组nums
,请你在所有可能的子序列中找到最长的和谐子序列的长度
python代码解法:
class Solution:
def findLHS(self, nums: List[int]) -> int:
if len(nums) <= 1:
return 0
nums.sort()
left, right = 0, 0
ans = 0
while right < len(nums):
if nums[right] - nums[left] > 1:
left += 1
if nums[right] - nums[left] == 1:
ans = max(ans, right - left + 1)
right += 1
return ans
Leetcode209:长度最小的子数组:中等题 (详情点击链接见原题)
给定一个含有
n
个正整数的数组和一个正整数target
找出该数组中满足其总和大于等于target
的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回0
python代码解法:
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
total = 0
left, right = 0, 0
res = float('inf') # res用来保存连续子数组的最短长度
if sum(nums) < target:
return 0
while right < len(nums):
total += nums[right]
while total >= target:
res = min(res, right - left + 1)
total -= nums[left]
left += 1
right += 1
return res
Leetcode1004:最大连续1的个数III:中等题 (详情点击链接见原题)
给定一个二进制数组
nums
和一个整数k
,如果可以翻转最多k
个0
,则返回 数组中连续1
的最大个数
python代码解法:
class Solution:
def longestOnes(self, nums: List[int], k: int) -> int:
left, right = 0, 0
res = 0
while right < len(nums):
if nums[right] == 0:
k -= 1
while k < 0:
if nums[left] == 0: # 当将左指针指向的 0 移出滑动窗口时
k += 1
left += 1
res = max(res, right - left + 1)
right += 1
return res
Leetcode424. 替换后的最长重复字符 / Leetcode2024. 考试的最大困扰度:中等题 (详情点击链接见原题)
给你一个字符串
s
和一个整数k
。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行k
次。
如果K = 0
,本题就变成了求解字符串中最长连续子串长度的问题
如果K > 0
,则变成了允许我们变换子串中的 K
个字符能够变成一个连续串
historyCharMax
保存滑动窗口内相同字母出现次数的历史最大值,通过判断滑动窗口宽度 right - left + 1
是否大于 historyCharMax + K
来决定窗口是否做滑动,否则窗口就扩张
问题的关键在于如何判断一个字符串改变 K
个字符能够变成一个连续串,如果当前窗口中 出现次数最多的字符个数 + K
大于串长度,则窗口扩张,否则窗口收缩
当窗口触达字符串末尾时,运算结束,窗口宽度为最终结果
核心要点:
count
记录的是窗口里字符出现的次数,是窗口里的,所以左窗口右移后,记得将移出去的元素个数 -1python代码解法:
class Solution:
def characterReplacement(self, s: str, k: int) -> int:
left, right = 0, 0
count = Counter()
historyCharMax = 0
while right < len(s):
count[s[right]] += 1
historyCharMax = max(historyCharMax, count[s[right]])
if right - left + 1 > historyCharMax + k: # 如果当前窗口的大小比历史窗口中出现次数最多的字母次数 + k 还大,证明k不足以将当前窗口全部替换成同一个字母,所以窗口左移
count[s[left]] -= 1
left += 1
right += 1
return right - left
这题的难点不同于一般的滑窗,这里滑窗内部的元素不一定满足条件,即滑窗没有被维护,historyCharMax
并不是当前窗口内出现次数最多字母的次数,而是历史窗口中出现次数最多字母的次数
Leetcode1208:尽可能使字符串相等:中等题 (详情点击链接见原题)
给你两个长度相同的字符串,
s
和t
。
将s
中的第i
个字符变到t
中的第i
个字符需要|s[i] - t[i]|
的开销(开销可能为0
),也就是两个字符的ASCII
码值的差的绝对值
python代码解法:
class Solution:
def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
left, right = 0, 0
ans = 0
while right < len(s):
maxCost -= abs(ord(s[right]) - ord(t[right]))
while maxCost < 0:
maxCost += abs(ord(s[left]) - ord(t[left]))
left += 1
ans = max(ans, right - left + 1)
right += 1
return ans
Leetcode1234:替换子串得到平衡字符串:中等题 (详情点击链接见原题)
有一个只含有
'Q'
,'W'
,'E'
,'R'
四种字符,且长度为n
的字符串。
假如在该字符串中,这四个字符都恰好出现n/4
次,那么它就是一个「平衡字符串」
Leetcode1456:定长子串中元音的最大数目:中等题 (详情点击链接见原题)
给你字符串
s
和整数k
。
请返回字符串s
中长度为k
的单个子字符串中可能包含的最大元音字母数
python代码解法:
class Solution:
def maxVowels(self, s: str, k: int) -> int:
vowels = ['a', 'e', 'i', 'o', 'u']
left, right = 0, 0
count = 0
max_count = 0
while k > 1:
if s[right] in vowels:
count += 1
max_count = max(count, max_count)
right += 1
k -= 1
while right < len(s):
if s[right] in vowels:
count += 1
max_count = max(count, max_count)
right += 1
if s[left] in vowels:
count -= 1
max_count = max(count, max_count)
left += 1
return max_count
Leetcode187:重复的DNA序列:中等题 (详情点击链接见原题)
给定一个表示
DNA
序列 的字符串s
,返回所有在DNA
分子中出现不止一次的 长度为10
的序列(子字符串)。你可以按 任意顺序 返回答案
解题思路:
从左到右处理字符串 s
,使用滑动窗口得到每个以 s[i]
为结尾且长度为 10
的子串,同时使用哈希表记录每个子串的出现次数,如果该子串出现次数超过一次则加入答案
注意:为了防止相同的子串重复添加到答案而又不使用常数较大的 Set
结构,可以规定当且仅当该子串在之前出现过一次(加上本次恰好为两次时)将子串加入答案
python代码解法:
from collections import Counter
class Solution:
def findRepeatedDnaSequences(self, s: str) -> List[str]:
left, right = 0, 9
ans = []
count = Counter()
while right < len(s):
if right - left + 1 == 10:
count[s[left: right + 1]] += 1
if count[s[left: right + 1]] > 1 and s[left: right + 1] not in ans:
ans.append(s[left: right + 1])
left += 1
right += 1
return ans
Leetcode1052:爱生气的书店老板:中等题 (详情点击链接见原题)
有一个书店老板,他的书店开了
n
分钟。每分钟都有一些顾客进入这家商店。给定一个长度为n
的整数数组customers
,其中customers[i]
是在第i
分钟开始时进入商店的顾客数量,所有这些顾客在第i
分钟结束后离开
python代码解法:
class Solution:
def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int:
ans = 0
for i in range(0, len(customers)):
if grumpy[i] == 0:
ans += customers[i] # 将原本就满意的客户加入答案
customers[i] = 0 # 将对应的customers[i]变为0
# 在customer中找到连续一段长度为minutes的子数组使得其总和最大
left, right = 0, 0
max_customers = 0
total = 0
while right < len(customers):
total += customers[right]
if right - left + 1 >= minutes:
max_customers = max(max_customers, total)
total -= customers[left]
left += 1
right += 1
return max_customers + ans
Leetcode904:水果成篮:中等题 (详情点击链接见原题)
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组
fruits
表示,其中fruits[i]
是第i
棵树上的水果 种类
解题思路:统计最大的连续的数组长度,有树的类型限制连续移动,可以用滑动窗口解决连续数组问题找出最长子数组使最多包含两种水果
python代码解法:
from collections import Counter
from typing import List
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
temp = Counter()
left, right = 0, 0
ans = 0
while right < len(fruits):
temp[fruits[right]] += 1 # 1.将右边界的元素添加至滑动窗口中
while len(temp) > 2: # 2.当滑动窗口中树的种类大于2,停止扩张右边界,开始收缩左边界
if temp[fruits[left]] != 0: # 3.当左指针指向的元素在滑动窗口中
temp[fruits[left]] -= 1 # 4.移除窗口中左指针指向的元素
if temp[fruits[left]] == 0: # 5.如果该元素为0,则将该类型的元素pop掉,留着统计下一个种类的元素
temp.pop(fruits[left])
left += 1
ans = max(ans, right - left + 1)
right += 1
return ans
Leetcode1493:删掉一个元素以后全为 1 的最长子数组:中等题 (详情点击链接见原题)
给你一个二进制数组
nums
,你需要从中删掉一个元素。
请你在删掉元素的结果数组中,返回最长的且只包含1
的非空子数组的长度。
如果不存在这样的子数组,请返回0
。
python代码解法:
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
left, right = 0, 0
zero_count = 0
ans = 0
while right < len(nums):
if nums[right] == 0:
zero_count += 1
if zero_count > 1:
if nums[left] == 0:
zero_count -= 1
left += 1
if zero_count <= 1:
ans = max(ans, right - left + 1)
right += 1
return ans - 1
Leetcode713. 乘积小于 K 的子数组:中等题 (详情点击链接见原题)
给你一个整数数组
nums
和一个整数k
,请你返回子数组内所有元素的乘积严格小于k
的连续子数组的数目
python代码解法:
class Solution:
def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
left, right = 0, 0
ans = 0
temp = 1
while right < len(nums):
temp *= nums[right]
while temp >= k:
temp //= nums[left]
left += 1
# 每次右指针移到一个新位置,应该加上x种数组组合
# nums[right]
# nums[right - 1], nums[right]
# nums[left],...nums[right - 1], nums[right]
ans += (right - left + 1)
right += 1
return ans
Leetcode2904. 最短且字典序最小的美丽子字符串:中等题 (详情点击链接见原题)
给你一个二进制字符串
s
和一个正整数k
。
如果s
的某个子字符串中1
的个数恰好等于k
,则称这个子字符串是一个 美丽子字符串
python代码解法:
class Solution:
def shortestBeautifulSubstring(self, s: str, k: int) -> str:
if s.count('1') < k:
return ''
ans = s # 初始化为 s
left, right = 0, 0
count = 0
while right < len(s):
if s[right] == '1':
count += 1
while count > k or s[left] == '0':
if s[left] == '1':
count -= 1
left += 1
if count == k:
temp = s[left: right + 1]
if len(temp) < len(ans) or (len(temp) == len(ans) and temp < ans):
ans = temp
right += 1
return ans
Leetcode219:存在重复元素II:简单题 (详情点击链接见原题)
给你一个整数数组
nums
和一个整数k
,判断数组中是否存在两个 不同的索引i
和j
,满足nums[i] == nums[j]
且abs(i - j) <= k
。如果存在,返回true
;否则,返回false
python代码解法:
from collections import Counter
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
left, right = 0, 0
slide_window = Counter()
while right < len(nums):
if nums[right] in slide_window:
if slide_window[nums[right]] >= 1:
return True
slide_window[nums[right]] += 1
if right - left >= k:
slide_window[nums[left]] -= 1
left += 1
right += 1
return False
Leetcode3-无重复字符的最长子串:中等题 (详情点击链接见原题)
right
扩大窗口即加入字符时,应该更新哪些数据?初始化
Counter(用字典也行)
记录滑动窗口中的元素以及元素出现的次数,right
向右滑扫描s
的过程中将元素和元素出现的次数记录在Counter
中
当滑动窗口中出现次数大于
1
的元素(即出现重复字符时)窗口应该停止扩大
left
指向的元素时需要移出滑动窗口
的元素,把他在滑动窗口
中出现的次数-1
在窗口进行扩大的时候进行更新,题目求无重复字符最长子串,故我们在这里对上次记录的结果和新的满足条件的窗口
(right - left)
取一个最大值
python代码解法:
from collections import Counter
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
window = Counter()
left, right = 0, 0
res = 0
while right < len(s):
window[s[right]] += 1
while window[s[right]] > 1:
window[s[left]] -= 1
left += 1 # 左指针向→滑动
right += 1 # 右指针向→滑动
res = max(res, right - left)
return res
Leetcode567-字符串的排列:中等题 (详情点击链接见原题)
给你两个字符串
s1
和s2
,写一个函数来判断s2
是否包含s1
的排列。如果是,返回true
;否则,返回false
学过排列组合的同学可以知道
如:ABC
的排列有 ABC
,ACB
,BCA
,BAC
,CAB
,CBA
6种结果
题目要求 s2
中是否包含 s1
的排列,所以我们应在 滑动窗口长度即right - left
等于 s1
子串的长度时停止扩大进行检查
相较于上题,窗口在停止扩大的时候更新结果,我们比较窗口内的有效字符
个数即可断定 s2
中是否包含 s1
中的排列
while right - left == len(s1):
if valid == len(need):
return True
解题思路:
由于排列不会改变字符串中每个字符的个数,所以只有当两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列
用一个哈希表对滑动窗口中的元素进行计数
1.维护一个窗口大小为 len(s1)
的滑动窗口
2.在滑动窗口往右滑的过程中
3.用 match 存储滑动窗口内的字符和 s1中的字符的匹配数
直接附上该题完整解法的Python代码
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
left, right = 0, 0
slide_window = {
}
count = Counter(s1)
match = 0
while right < len(s2):
slide_window[s2[right]] = slide_window.get(s2[right], 0) + 1
if s2[right] in count:
if slide_window[s2[right]] == count[s2[right]]:
match += 1
right += 1
while right - left >= len(s1): # 开始移动左指针收缩左窗口
if match == len(count):
return True
if s2[left] in count:
if slide_window[s2[left]] == count[s2[left]]: # 判断即将移出窗口的元素是否是==s1中的匹配数
match -= 1
slide_window[s2[left]] -= 1
left += 1
return match == len(s1)
Leetcode438-找到字符串中所有的字母异位词:中等题 (详情点击链接见原题)
给定两个字符串
s
和p
,找到s
中所有p
的异位词的子串,返回这些子串的起始索引
注: 异位词是指有相同字母重新排列形成的字符串(包括相同的字符串)
字母异位词的本质就是排列,换了一种说法而已
本题相较于上一题字符串的排列
改动点如下,我们只需在 s
中找到一个 p
的排列后记录下这个位置索引,跟上题不能说差不多简直就是一模一样,在滑动窗口长度
等于p的长度
窗口暂停扩大的时候更新结果
result = []
while right - left == len(t):
if valid == len(need):
result.append(left)
附上该题完整的Python代码
from collections import Counter
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
slide_window = {
}
left, right = 0, 0
valid = 0
count = Counter(p)
result = [] # 保存结果集
while right < len(s):
slide_window[s[right]] = slide_window.get(s[right], 0) + 1
if slide_window[s[right]] == count[s[right]]:
valid += 1
right += 1
while right - left >= len(p): # 滑动窗口维持 p 字符的长度
if valid == len(count): # 如果滑窗中的有效字符等于count的有效长度
result.append(left) # 将起始位置加入结果集
if slide_window[s[left]] == count[s[left]]:
valid -= 1
slide_window[s[left]] -= 1
left += 1
return result
Leetcode76-最小覆盖子串:困难题 (详情点击链接见原题)
给你一个字符串
s
,一个字符串t
,请你在字符串s
中找出包含t
所有字母的最小子串,如果s
中不存在涵盖t所有字符的子串则返回空串
注: 对于t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量
解题思路
由于 t
中可能存在重复字符,所以我们可以借助字典(哈希表)来对t
中的字符和字符出现的次数进行计数,这里我们借助于python
的内置collections
库中的Counter
,其实用字典也一样,这里纯属偷懒
from collections import Counter
need = Counter(t)
对子串做好记录以后我们还需对左右指针维护的滑动窗口内的元素和每个元素的出现次数进行统计
window = Counter() # 初始化空字典用来统计左右指针滑动的过程中滑动窗口内的元素和元素出现的次数
# 双指针
left, right = 0, 0
valid = 0 # 有效匹配字符个数,滑窗内的字符以及该字符出现的次数和==子串中的对应字符valid才+1
start = 0 # 用来记录最小子串的起始覆盖索引
substring_len = float('inf') # s中包含t中所有字符的最小子串的长度,初始化为无穷大,方便后续更新覆盖
1.当移动 right
扩大窗口即加入字符时,应该更新哪些数据?
右指针向右滑动遍历s串
,窗口扩大,window
记录窗口内的元素及元素出现的次数
对于即将加入窗口的新元素(即right指针所指的元素)
我们不仅需要判断它是否是子串中的元素,如果是窗口内的对应元素数量+1
,
还要判断滑动窗口
中元素的数量和子串中对应元素的数量相等,则有效匹配字符个数valid+=1
while right < len(s):
if s[right] in list(need.keys()):
window[s[right]] += 1 # 窗口内对应元素数量+1
if window[s[right]] == need[s[right]]: # 如果对应元素数量相等则对valid+1
valid += 1
right += 1 # 右指针向→滑动
2.什么条件下窗口应该暂停扩大?
在右指针向右滑的过程中一旦滑动窗口
和子串
中的元素及元素出现的次数都能匹配上即 valid == len(need)
,说明滑动窗口
已经包含t子串
,此时右指针应该暂停扩大
注:我们要的结果是在扩大窗口时还是缩小窗口还是窗口暂停扩大的时候进行更新?
本题中我们是在窗口暂停扩大的时候判断此时的窗口长度是否小于之前的记录的窗口长度,如果小于则记录下
窗口的起始位置
和更新s中包含t子串的子串长度
while valid == len(need):
if right - left < substring_len:
start = left # 记录下最小子串的起始覆盖索引
substring_len = right - left # 更新s中包含t子串的子串长度
注意上面的黄色字体,上面的代码逻辑发生在右指针向右滑的过程中,所以上面的代码应该
嵌套在右指针向右滑动的大循环中
3.当移动left缩小窗口,即移出字符时应该更新哪些数据?
和移动右指针将元素加入到滑动窗口
中的操作相同,当我们移动左指针收缩窗口将元素从窗口中移出的时候
我们不仅需要判断它是否是子串中的元素,如果是窗口内的对应元素数量 - 1
,
还要判断滑动窗口
中该元素的数量和子串中对应该元素的数量相等,如果相等那么移出该元素必定导致有效匹配字符个数-1即valid -= 1
if s[left] in list(need.keys()):
if window[s[left]] == need[s[left]]: # 因为移出字符在
valid -= 1
window[s[left]] -= 1 # 滑动窗口内对应元素的数量-1
left += 1 # 左指针向→滑动
Python完整代码
class Solution:
def minWindow(self, s: str, t: str) -> str:
need, window = Counter(t), Counter() # need用于记录需要匹配的t串中的字符以及字符出现的频率
left, right = 0, 0
valid = 0 # valid用于记录已经匹配成功的有效字符的个数
start = 0 # 记录最小子串的起始覆盖索引,初始化为0
substring_len = float('inf') # 将长度初始化为无穷大
while right < len(s):
if s[right] in list(need.keys()):
window[s[right]] += 1
if window[s[right]] == need[s[right]]: # 当对应字符出现的频率相等,对应的 valid + 1
valid += 1
right += 1 # 右指针向→滑动
# 经过上面的处理之后已经可以将
while valid == len(need):
if right - left < substring_len:
start = left # 记录下最小子串的起始覆盖索引
substring_len = right - left
if s[left] in list(need.keys()):
if window[s[left]] == need[s[left]]:
valid -= 1
window[s[left]] -= 1
left += 1 # 左指针向→滑动
return s[start:start + substring_len] if substring_len != float('inf') else ""
Leetcode1695. 删除子数组的最大得分:中等题 (详情点击链接见原题)
给你一个正整数数组
nums
,请你从中删除一个含有 若干不同元素 的子数组。删除子数组的 得分 就是子数组各元素之 和 。
返回 只删除一个 子数组可获得的 最大得分
Python完整代码
class Solution:
def maximumUniqueSubarray(self, nums: List[int]) -> int:
window_sum = 0
ans = 0
slide_window = Counter()
left, right = 0, 0
while right < len(nums):
slide_window[nums[right]] += 1
window_sum += nums[right]
while slide_window[nums[right]] > 1:
window_sum -= nums[left]
slide_window[nums[left]] -= 1
left += 1
ans = max(ans, window_sum)
right += 1
return ans
Leetcode30. 串联所有单词的子串:困难题 (详情点击链接见原题)
给定一个字符串
s
和一个字符串数组words
。words
中所有字符串 长度相同。s
中的 串联子串 是指一个包含words
中所有字符串以任意顺序排列连接起来的子串
Python完整代码
from collections import Counter
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
word_len = len(words[0]) # 单个单词的长度
words_map = Counter(words) # 统计单词和单词出现的频率
ans = []
for i in range(len(words[0])): # 试点
valid = 0 # valid用来记录有效匹配个数
left = i
right = i
hash_map = Counter()
while right < len(s):
if s[right:right + word_len] in words_map:
hash_map[s[right:right + word_len]] += 1
if hash_map[s[right:right + word_len]] == words_map[s[right:right + word_len]]:
valid += 1
right += word_len # 从下个单词的起始位置开始匹配
if right - left == len(words) * len(words[0]):
if valid == len(words_map):
ans.append(left)
if s[left:left + word_len] in words_map:
if hash_map[s[left:left + word_len]] == words_map[s[left:left + word_len]]:
valid -= 1
hash_map[s[left:left + word_len]] -= 1
left += word_len
return ans
Leetcode2799. 统计完全子数组的数目:中等题 (详情点击链接见原题)
给你一个由 正 整数组成的数组
nums
。如果数组中的某个子数组满足下述条件,则称之为 完全子数组
解题思路
用 distinct
表示整个数组不同元素的数目,使用哈希表记录滑动窗口中每个元素的出现次数,对每个右端点执行如下操作
在哈希表中将 nums[right]
的出现次数 +1
当哈希表中的元素个数等于 distinct
时执行如下操作
nums[left]
的出现次数 -1
,如果 nums[left]
的次数变为 0
,将 nums[left]
从哈希表中移除,将 left
右移一位以 right
作为结束下标的完全子数组的数目是 left
,将完全子数组的数目增加 left
left > 0
,则以 right
作为结束下标的最短完全子数组的开始下标是 left - 1
,因此结束下标是 right
且开始下标在范围 [0, left - 1]
中的子数组都是完全子数组,以 right
作为结束下标的完全子数组的数目是 left
left= 0
,则不存在以 right
作为结束下标的完全子数组Python完整代码
class Solution:
def countCompleteSubarrays(self, nums: List[int]) -> int:
n = len(set(nums))
count = Counter()
ans = 0
right, left = 0, 0
while right < len(nums):
count[nums[right]] += 1
while len(count) == n:
count[nums[left]] -= 1
if count[nums[left]] == 0:
count.pop(nums[left])
left += 1
ans += left
right += 1
return ans
Leetcode1438. 绝对差不超过限制的最长连续子数组:中等题 (详情点击链接见原题)
给你一个整数数组
nums
,和一个表示限制的整数limit
,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于limit
解题思路
要求窗口的最大长度,我们必须时刻知道当前窗口内的最值,才能判断是否满足限制
此题的难点在于当一个元素入窗或者出窗时,如何以最小的时间开销找到新的窗口内的最大值和最小值
很容易想到用堆来记录最值,但是插入删除操作是 O(logn)
级别,还有没有更好的解决方案呢?
双端队列:插入删除头尾元素都是O(1)
min_q
: (从队头—>队尾)从小到大存储窗口中的元素
max_q
: (从队头—>队尾)从大到小存储窗口中的元素
Python完整代码
class Solution:
def longestSubarray(self, nums: List[int], limit: int) -> int:
right, left = 0, 0
min_q = deque()
max_q = deque()
ans = 0
while right < len(nums):
while min_q and nums[right] < min_q[-1]:
min_q.pop()
while max_q and nums[right] > max_q[-1]:
max_q.pop()
min_q.append(nums[right])
max_q.append(nums[right])
while max_q[0] - min_q[0] > limit:
if min_q[0] == nums[left]:
min_q.popleft()
if max_q[0] == nums[left]:
max_q.popleft()
left += 1
ans = max(ans, right - left + 1)
right += 1
return ans
在我们对滑动窗口进行了由浅入深、由难到易的介绍后,博主在最后为大家介绍一些高频面试练手题,算法题没有固定模板,对于可以总结框架的题型我们对它进行分析打磨,节省大家在刷题准备面试过程中的时间成本,提高大家的效率
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数