leetcode 3 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# Step 1: 定义需要维护的变量, 本题求最大长度,所以需要定义max_len,
# 该题又涉及去重,因此还需要一个哈希表
max_len, hashmap = 0, {}
# Step 2: 定义窗口的首尾端 (start, end), 然后滑动窗口
start = 0
for end in range(len(s)):
# Step 3
# 更新需要维护的变量 (max_len, hashmap)
# i.e. 把窗口末端元素加入哈希表,使其频率加1,并且更新最大长度
hashmap[s[end]] = hashmap.get(s[end], 0) + 1
if len(hashmap) == end - start + 1:
#不重复的元素个数和字符子串当前长度一样,判断是否是历史最长的字符串
max_len = max(max_len, end - start + 1)
# Step 4:
# 根据题意, 题目的窗口长度可变: 这个时候一般涉及到窗口是否合法的问题
# 这时要用一个while去不断移动窗口左指针, 从而剔除非法元素直到窗口再次合法
# 所以需要不断移动窗口左指针直到窗口再次合法, 同时提前更新需要维护的变量 (hashmap)
while end - start + 1 > len(hashmap):
head = s[start]
hashmap[head] -= 1
if hashmap[head] == 0:
del hashmap[head]
start += 1
# Step 5: 返回答案 (最大长度)
return max_len
leetcode 159 至多包含两个不同字符的最长子串
给定一个字符串 s ,找出 至多 包含两个不同字符的最长子串 t ,并返回该子串的长度。
示例 1:
输入: “eceba”
输出: 3
解释: t 是 “ece”,长度为3。
class Solution:
def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
n = len(s)
char_count={} # key:字符 value:字符个数
l=0
res=0
for r in range(n):
char_count[s[r]]=char_count.get(s[r],0)+1
if len(char_count)<=2: #最多只有两种字符 在此情况找最长字符
res=max(res, r-l+1)
while len(char_count)>2:# # l右移直到只有两种字符,同时更新字典
char_count[s[l]]-=1
if char_count[s[l]]==0:
del char_count[s[l]]
l+=1
return res
leetcode 209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0 。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n=len(nums)
l,r=0,0
curr_sum=0
res=n+1
for r in range(n):
curr_sum+=nums[r]
while curr_sum>=target:
res=min(res,r-l+1)
curr_sum-=nums[l]
l+=1
return 0 if res==n+1 else res
leetcode 487 最大连续1的个数 II
给定一个二进制数组 nums ,如果最多可以翻转一个 0 ,则返回数组中连续 1 的最大个数。
示例 1:
输入:nums = [1,0,1,1,0]
输出:4
解释:翻转第一个 0 可以得到最长的连续 1。
示例 2:
输入:nums = [1,0,1,1,0,1]
输出:4
class Solution:
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
n = len(nums)
l=0
res=-1
curr_sum=0
for r in range(n):
curr_sum+=nums[r]
if r-l+1 <=curr_sum+1:
res=max(res, r-l+1)
while r-l+1 > curr_sum+1:
curr_sum-=nums[l]
l+=1
return res
1004. 最大连续1的个数 III
给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。
示例 1:
输入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
示例 2:
输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
class Solution:
def longestOnes(self, nums: List[int], k: int) -> int:
n = len(nums)
l=0
curr_sum = 0
res = 0
for r in range(n):
curr_sum+=nums[r]
if r-l+1 <= curr_sum+k:
res = max(res, r-l+1)
while r-l+1 > curr_sum+k:
curr_sum-=nums[l]
l+=1
return res
leetcode 1208 尽可能使字符串相等
给你两个长度相同的字符串,s 和 t。将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。
示例 1:
输入:s = “abcd”, t = “bcdf”, maxCost = 3
输出:3
解释:s 中的 “abc” 可以变为 “bcd”。开销为 3,所以最大长度为 3。
示例 2:
输入:s = “abcd”, t = “cdef”, maxCost = 3
输出:1
解释:s 中的任一字符要想变成 t 中对应的字符,其开销都是 2。因此,最大长度为 1。
示例 3:
输入:s = “abcd”, t = “acde”, maxCost = 0
输出:1
解释:a -> a, cost = 0,字符串未发生变化,所以最大长度为 1。
class Solution:
def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
#abcd->bcdf maxCost=3; 最长长度为abc到bcd是1+1+1,此时cost是3
#abcd->cdef maxCost=3; 最长长度为a到c或者b到d是2;cost是2,如果ab到cd,那么cost就是2+2=4
#abcd->acde maxCost=0;最长长度是a到a是1,此时cost是0;注意这里不能是cd到cd,因为两个字符串的index对不上
# ord('a')可以找到’a‘的ascii码
n = len(s)
cost = 0
l=0
max_length=0
for r in range(n):
cost+=abs(ord(s[r])- ord(t[r]))
if cost<=maxCost:
max_length=max(max_length,r-l+1)
while cost > maxCost : # 一个可变长的窗口
cost -= abs(ord(s[l]) - ord(t[l]))
l+=1
return max_length
leetcode 1493 删掉一个元素以后全为 1 的最长子数组
给你一个二进制数组 nums ,你需要从中删掉一个元素。
请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。
如果不存在这样的子数组,请返回 0 。
提示 1:
输入:nums = [1,1,0,1]
输出:3
解释:删掉位置 2 的数后,[1,1,1] 包含 3 个 1 。
示例 2:
输入:nums = [0,1,1,1,0,1,1,0,1]
输出:5
解释:删掉位置 4 的数字后,[0,1,1,1,1,1,0,1] 的最长全 1 子数组为 [1,1,1,1,1] 。
示例 3:
输入:nums = [1,1,1]
输出:2
解释:你必须要删除一个元素。
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
#对于只删除了一个元素的子数组,滑动窗口的和=r-l+1-1=r-l
#所以结果就是找到最长子数组,并且r-l=sum(子数组)
n = len(nums)
l = 0
max_length = 0
curr_length = 0
curr_sum = 0
for r in range(n):
curr_sum+=nums[r]
if curr_sum >= r-l: #因为必须要删除一个元素,所以curr_rum==r-l或者curr_sum==r-l+1
max_length = max(max_length, r-l)
while r-l > curr_sum:
curr_sum-=nums[l]
l+=1
return max_length
leetcode 904 水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
示例 1:
输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。
示例 2:
输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。
示例 3:
输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。
示例 4:
输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
#n=len(fruits) 一共有n棵树;fruits[i]是水果种类;只能选择两种水果
#从哪里开始采摘很重要,比如[3,3,3,1,2,1,1,2,3,3,4]
#如果从第一个3开始采摘,那么只能采摘3 3 3 1,碰到下一个2就要停止
#简化题目:对于nums,找到一个连续子数组,其中只有两种不同整数,找到最长子数组
n=len(fruits)
if n==1:
return 1
value_count = {}
l , res = 0, 0
for r in range(n):
value_count[fruits[r]]=value_count.get(fruits[r],0)+1
if len(value_count)<=2: #这里需要考虑[1,1,1,1]这种情况,所以不能用==2
res = max(res, r-l+1)
while len(value_count)==3:
value_count[fruits[l]]-=1
if value_count[fruits[l]]==0:
del value_count[fruits[l]]
l+=1
return res