力扣 hot100 Day2:滑动窗口(pdd算法面试手撕)/子串/普通数组
3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 :
输入: s = "abcabcbb"
输出: 3
思路 : 设置滑动窗口 while控制窗口移动去重 注意对输入为空串的处理
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s: return 0 #对输入空串单独处理
start=0
maxlen=0
for end in range(len(s)):
while s[end] in s[start:end]:
start+=1
maxlen=max(maxlen, end-start+1)
return maxlen
438. 字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
示例 :
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
**思路 :分别对p和窗口字符计数,每次移动滑动窗口最左侧的字符计数-1,新移入的字符计数+1,若window计数数组==p计数数组,则将滑动窗口新的开头(left+1)纳入结果 **
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
lens,lenp=len(s),len(p)
if lens<lenp: return []
res=[]
cntp,window=[0]*26,[0]*26
for c in p: cntp[ord(c)-ord('a')]+=1
for i in range(lenp):
window[ord(s[i])-ord('a')]+=1
if window==cntp: res.append(0) #第一个窗口
for left in range(lens-lenp):
window[ord(s[left])-ord('a')]-=1
window[ord(s[left+lenp])-ord('a')]+=1
if window==cntp: res.append(left+1)
return res
pdd算法面试手撕
给定长度为 n 的整数数组 nums,滑动窗口长度 k,阈值 t。 元素值 <= t 为"正常",> t 为"异常"。 对每个窗口,若异常元素数量严格大于 ⌊k/2⌋,则该窗口为"异常窗口"。 输出数组中所有异常窗口的起始索引。
示例 :
输入:nums = [1,6,7,2,8,3,9,10], k=4, t=5
输出:[1, 4]
**思路 : **
class Solution:
def count_abnormal_windows(nums, k, t):
lennum=len(nums)
thresh=k//2
res=[]
#第一个窗口中异常数量
abnormal_cnt=sum(1 for i in range(k) if nums[i]>t)
if abnormal_cnt>thresh: res.append(0)
for left in range(lennum-k):
if nums[left]> t: abnormal_cnt-=1
if nums[left+k] >t: abnormal_cnt+=1
if abnormal_cnt>thresh : res.append(left+1)
return res
560. 和为k的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。子数组是数组中元素的连续非空序列。
示例 :
输入:nums = [1,1,1], k = 2
输出:2
思路 : 把任意子数组都表示成两个前缀和的差(数组不满足单调性时考虑用前缀和,而不是滑动窗口)
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cnt=defaultdict(int) # 前缀和值 → 出现次数
cnt[0]=1 # 前缀和为0出现1次(空前缀,处理从开头开始的子数组)
perfix=ans=0 perfix记录当前前缀和 ans为前缀和=k的数目
for num in nums:
perfix+=num #算到当前位置的前缀和
ans+=cnt[perfix-k] # 查有多少个前缀和 = prefix-k
cnt[perfix]+=1 #把当前前缀和记入
return ans
53. 最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 :
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
思路 : 动态规划
需要维护两个变量,当前最大和(以当前元素结尾)与全局最大和(遍历过程中的最大值),状态转移-对于每个元素x,决策是“加入前一子数组”还是“重新开始”,公式为dp[i]=max(nums[i],dp[i-1]+nums[i])
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
cur=maxsum=nums[0]
for x in nums[1:] :
cur=max(x,x+cur) # 要么接上前面,要么从 x 重开
maxsum=max(maxsum,cur)
return maxsum
56. 合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 :
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
思路 : 维护一个res[],遍历intervals中元素每次和res[-1]进行比较,分3种情况讨论
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
res=[]
intervals.sort(key=lambda x:x[0])
for x in intervals:
if not res: res.append(x) #开始时res为空,将intervals[0]加入
if x[0]<=res[-1][1] and x[1]<=res[-1][1] : res[-1]=res[-1] #两数都小于res[-1][1],结果直接将当前元素合并到前面,即res[-1]不需改变
elif x[0]<=res[-1][1] and x[1]>=res[-1][1] : res[-1][1]=x[1] #后一个数大于res[-1][1],res[-1][1]换成这个更大的数
else: res.append(x) #第三种情况,两区间不交,直接加入res中
return res
238. 除了自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除了 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
示例 :
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
思路 : 使用两个循环分别计算左侧乘积(直接算到ans中)和右侧乘积(用临时变量记录,再乘到ans中)
原数组: [1 2 3 4]
左部分的乘积: 1 1 1*2 1*2*3
右部分的乘积: 2*3*4 3*4 4 1
结果: 1*2*3*4 1*3*4 1*2*4 1*2*3*1
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
ans=[1]*len(nums)
tmp=1
#计算左侧
for i in range(1,len(nums)):
ans[i]=ans[i-1]*nums[i-1]
for i in range(len(nums)-2,-1,-1):
tmp*=nums[i+1]
ans*=tmp
return ans
浙公网安备 33010602011771号