左右指针,右指针右移动扩展,满足条件之后,左指针收缩。
// 模板
for () {
// 将新进来的右边的数据,计算进来
// 更新数据
// 判断窗口数据是否不满足要求了
while (窗口数据不满要求 && left < arrSize) {
// 移除left数据,更新窗口数据
left++;
}
// 此时的res是都满足条件的,计算res
res = right - left + 1
right++;
}
[LeetCode] 992. Subarrays with K Different Integers 有K个不同整数的子数组 - Grandyang - 博客园
class Solution(object):
def mostk(self,nums,k):
res=0
left=0
right=0
dict={}
while left<=right and rightk:
#如果value为1,直接删除;如果value大于1,减去1
if dict[nums[left]]==1:
del dict[nums[left]]
else:
dict[nums[left]]=dict[nums[left]]-1
left=left+1
res+=right-left+1
right=right+1
return res
def subarraysWithKDistinct(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
return self.mostk(nums,k)-self.mostk(nums,k-1)
[LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串 - Grandyang - 博客园
class Solution(object):
def lengthOfLongestSubstringTwoDistinct(self, s):
"""
:type s: str
:rtype: int
"""
#移动右指针,通过字典来判断,是否需要移动左指针
res=0
left=0
right=0
dict={}
while left<=right and right2:
#如果value为1,直接删除;如果value大于1,减去1
if dict[s[left]]==1:
del dict[s[left]]
else:
dict[s[left]]=dict[s[left]]-1
left=left+1
cur_res=right-left+1
if cur_res>res:
res=cur_res
right=right+1
return res
力扣
from collections import defaultdict
class Solution:
def minWindow(self, s: str, t: str) -> str:
'''
如果hs哈希表中包含ht哈希表中的所有字符,并且对应的个数都不小于ht哈希表中各个字符的个数,那么说明当前的窗口是可行的,可行中的长度最短的滑动窗口就是答案。
'''
if len(s) ht[s[left]]:#窗口内元素都符合,开始压缩窗口
hs[s[left]] -= 1
left += 1
if cnt == len(t):
if not res or right-left+1
class Solution:
def minWindow(self, s: str, t: str) -> str:
#哈希表计数
from collections import Counter
dic_t=Counter(t)
dic_s=Counter()
count=0
res_size=len(s)+1
res=''
#左右指针遍历,右指针的元素加入哈希表
left=0
right=0
while rightdic_t[s[left]]:
dic_s[s[left]]-=1
left+=1
#判断是否满足t的长度
if count==len(t):
cur_size=right-left+1
if cur_size
#双指针:移动右指针,发现不满足条件之后再收缩左指针
#左指针逐位置搜索,通过70/90个case。优化时应该考虑,从maps里判断收缩。
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def totalFruit(self, fruits):
res=0
left=0
right=0
while left<=right and right2:
right=right-1
break
cur = right - left + 1
res = max(res, cur)
left+=1
right=left
return res
fruits = [0,1,2,2]
# fruits = [3,3,3,1,2,1,1,2,3,3,4]
res=Solution().totalFruit(fruits)
print(res)
#右指针始终往右边移动。根据条件判断左指针是否收缩
def totalFruit2(self, fruits):
res=0
left=0
right=0
maps={}
while left<=right and right2 :
maps[fruits[left]]-=1
if maps[fruits[left]]==0:
del maps[fruits[left]]
left+=1
#计算
cur=right-left+1
res = max(res, cur)
right+=1
return res
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
#滑窗,当sum大于target时收缩左窗口,当sum等于target时计算一次结果
#注意是≥ target
left = 0
right = 0
cur_sum = 0
res = float("inf")
while right < len(nums):
cur_sum += nums[right]
#当cur_sum大于target时收缩左窗口
while cur_sum >= target:
cur_res = right - left + 1
res = min(cur_res,res)
cur_sum -= nums[left]
left += 1
right += 1
if res == float("inf"):
return 0
return res
队列中要存index。下面是我第一次写的,bug比较多:
1是没有存index, 而是存的值。
2是没有把队首元素弹出。
3是前缀和写法错误,
presum[j]-presum[i]表示的是nums[j]到nums[i+1],presum[j]-presum[i-1]表示的才是nums[j]到nums[i]
class Solution:
def shortestSubarray(self, nums: List[int], k: int) -> int:
#单调递增队列+前缀和
#前缀和数组
presum = [0 for _ in range(len(nums)+1)]
for i in range(1,len(nums)+1):
presum[i] = presum[i-1] + nums[i-1]
res = float("inf")
deq = deque()
for i in range(len(nums)+1):
#维护单调递增性
while deq and deq[-1] > presum[i]:
deq.pop()
#都弹出之后
deq.append(presum[i])
#计算target
if deq and deq[-1] - deq[0] >= k:
cur_res = len(deq)-1
res = min(res,cur_res)
if res == float("inf"):
return -1
return res
class Solution:
def shortestSubarray(self, nums, k):
res = float("inf")
# 1,2,3
# 1,3,6
#presum[j]-presum[i]表示的是nums[j]到nums[i+1],presum[j]-presum[i-1]表示的才是nums[j]到nums[i]
#前缀和
presum = [0 for _ in range(len(nums)+1)]
for i in range(1,len(presum)):
presum[i] = presum[i-1] + nums[i-1]
#维护一个单调递增队列,队尾-队首>=k,说明找到了一个符合要求的答案
from collections import deque
deq = deque()
for i in range(len(presum)):
#不满足单调性的话,弹出队尾
while deq and presum[deq[-1]] > presum[i]:
deq.pop()
#满足单调递增性
deq.append(i)
#计算一次,注意这里要用while,比如nums = [17,85,93,-45,-21],k = 150,结果是85,93而不是17,85,93
while presum[deq[-1]] - presum[deq[0]] >= k:
cur_res = deq[-1] - deq.popleft()
res = min(cur_res,res)
if res == float("inf"):
return -1
return res
class Solution {
public:
int minSwaps(vector& nums) {
int n = nums.size();
int cnt = accumulate(nums.begin(), nums.end(), 0);
if(cnt == n || cnt == 0 || cnt == 1)
return 0;
int ans = 0;
int temp = 0;
for(int i = 0; i < cnt; i ++)
if(nums[i] == 0)
temp ++;
ans = temp;
for(int i = 0; i < n + cnt - 1; i ++) //进行数组拼接
{
if(nums[(i + cnt) % n] == 0) //如果新进的元素是0,则交换次数加1
temp ++; //如果新出的元素是0,则交换次数减1
if(nums[i % n] == 0)
temp --;
ans = min(ans, temp);
}
return ans;
}
};
作者:Luna_
链接:https://leetcode-cn.com/problems/minimum-swaps-to-group-all-1s-together-ii/solution/hua-dong-chuang-kou-shu-zu-pin-jie-by-lu-bed2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
def minSwaps(self, nums: List[int]) -> int:
n = len(nums)
a = nums + nums
cnt1 = nums.count(1)
res = float('inf')
Window_len = cnt1
cur = nums[ :Window_len].count(1)
res = min(res, cnt1 - cur)
for r in range(Window_len, n * 2):
#--进r
if a[r] == 1:
cur += 1
#--弹l
l = r - Window_len
if a[l] == 1:
cur -= 1
#--更新res
res = min(res, cnt1 - cur)
return res
作者:Hanxin_Hanxin
链接:https://leetcode-cn.com/problems/minimum-swaps-to-group-all-1s-together-ii/solution/cpython3javago-1hua-dong-chuang-kou-by-h-l4dl/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
力扣
class Solution:
def minSwaps(self, nums: List[int]) -> int:
#窗口长度为1的个数,窗口里最少有几个0
count1=0
for i in range(len(nums)):
if nums[i]==1:
count1+=1
count0=0
for i in range(count1):
if nums[i]==0:
count0+=1
min_count0=count0
cur_index=count1
while cur_index
class Solution(object):
def longestOnes(self, A, K):
N = len(A)
res = 0
left, right = 0, 0
zeros = 0
while right < N:
if A[right] == 0:
zeros += 1
while zeros > K:
if A[left] == 0:
zeros -= 1
left += 1
res = max(res, right - left + 1)
right += 1
return res
作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua-dong-chuang-kou-mo-ban-mia-f76z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
public int longestOnes(int[] A, int K) {
int left = 0;//窗口左边的位置
int maxWindow = 0;//窗口的最大值
int zeroCount = 0;//窗口中0的个数
for (int right = 0; right < A.length; right++) {
if (A[right] == 0) {
zeroCount++;
}
//如果窗口中0的个数超过了K,要缩小窗口的大小,直到0的个数
//不大于K位置
while (zeroCount > K) {
if (A[left++] == 0)
zeroCount--;
}
//记录最大的窗口
maxWindow = Math.max(maxWindow, right - left + 1);
}
return maxWindow;
}
作者:sdwwld
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/hua-dong-chuang-kou-de-liang-chong-jie-j-8ses/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
left=0
right=0
count0=0
res=0
while right1:
if nums[left]==0:
count0-=1
left+=1
#right指针右边移动
if nums[right]==0:
count0+=1
cur=right-1-left+1-1
else:
cur=right-left+1-1
res=max(res,cur)
right+=1
return res
题目要求时间复杂度o(n),空间复杂度o(1)
两种解法:
1.最长上升子序列问题,leetcode-最大最小问题-v2_MaYingColdPlay的博客-CSDN博客,这个时间复杂度是o(n^2),会超时。
2.双指针解法,满足时间复杂度要求。
# 双指针,一个min_val,一个middle_val,如果第三个比前两个大,返回true
class Solution(object):
def increasingTriplet(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
min_val=float("inf")
middle_val=float("inf")
for val in nums:
if val <= min_val:
min_val = val
elif val <= middle_val:
middle_val = val
else:
return True
#说明当前值比min_val和middle_val都大
return False
class Solution(object):
# 小时:分钟格式的数据。例如 22:13,22:14
# 先按照小时排序,再按照分钟排序
def convert(self,n1,n2):
#2213,2314
s1_hour=int(str(n1)[:2])
s2_hour=int(str(n2)[:2])
s1_minutes=int(str(n1)[2:])
s2_minutes =int(str(n2)[2:])
#如果第二个分钟小于第一个分钟,小时差减去1,分钟差是s2_minutes+60-s1_minutes
if s2_minutes
def func(timePoints):
timePoints.sort()
left = -1
right = 0
min_time = 24*60
n = len(timePoints)
if n > 1440:
return 0
while right < len(timePoints):
x = timePoints[left].split(":") # 数据
y = timePoints[right].split(":")
if int(y[1]) >= int(x[1]):
time = (int(y[0]) - int(x[0]))*60 + (int(y[1]) - int(x[1]))
else:
time = (int(y[0]) - 1 - int(x[0]))*60 + int(y[1]) + 60 - int(x[1])
if min(abs(time),1440-abs(time)) < min_time:
min_time = min(abs(time),1440-abs(time))
left = left + 1
right = right + 1
return min_time
作者:lnnnnnnn
链接:https://leetcode-cn.com/problems/minimum-time-difference/solution/python3-pai-xu-by-lnnnnnnn-03qp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
记忆化递归,超时。用flag判断奇偶性就不超时。
class Solution:
def maxAlternatingSum(self, nums: List[int]) -> int:
cache={}
#每个元素的下标选或者不选两种选择
def dfs(index,child_index):
if (index,child_index) in cache:
return cache[(index,child_index)]
if index==len(nums):
return 0
a,b,c=0,0,0
#index不选
a=dfs(index+1,child_index)
#index选
if child_index%2==0:
b=dfs(index+1,child_index+1)+nums[index]
else:
c=dfs(index+1,child_index+1)-nums[index]
cache[(index,child_index)]=max(a,b,c)
return max(a,b,c)
#真实index,在子序列里的index
return dfs(0,0)
class Solution:
def maxAlternatingSum(self, nums: List[int]) -> int:
cache={}
#每个元素的下标选或者不选两种选择
def dfs(index,flag):
if (index,flag) in cache:
return cache[(index,flag)]
if index==len(nums):
return 0
a,b,c=0,0,0
#index不选
a=dfs(index+1,flag)
#index选
if flag:
b=dfs(index+1,False)+nums[index]
else:
c=dfs(index+1,True)-nums[index]
cache[(index,flag)]=max(a,b,c)
return max(a,b,c)
#真实index
#flag代表奇数偶数,flag=True为偶数
flag=True
return dfs(0,flag)
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
cnt, ans, firstMinus, lastMinus, minus = 0, 0, None, None, 0
for i in range(len(nums) + 1):
if i == len(nums) or nums[i] == 0: #遍历完成或者为0时,清空计数,更新ans
if minus % 2 == 0: #如果负数为偶数个,就不用管了
ans = max(ans, cnt)
else: #如果负数为奇数个,就去掉第一个或最后一个负数
ans = max(ans, cnt - firstMinus, lastMinus)
cnt, firstMinus, lastMinus, minus = 0, None, None, 0 #重新计数
elif nums[i] > 0:
cnt += 1
else:
if firstMinus == None: #记录下第一个和最后一个(此时最后一个就是第一个)
firstMinus = cnt + 1
lastMinus = cnt
elif lastMinus != None: #出现了第二个负数,此时更新最后一个负数的位置
lastMinus = cnt
minus += 1 #负数的个数
cnt += 1
return ans
#找到2个人休息时间重合的部分,看是否满足duration要求
#以slots1为基准
def testv2(slots1,slots2,duration):
slots1.sort()
slots2.sort()
for i in range(len(slots1)):
cur_left=slots1[i][0]
cur_right=slots1[i][1]
for j in range(len(slots2)):
#是否有交集
if slots2[j][0]cur_left:
left_new=max(cur_left,slots2[j][0])
right_new=min(cur_right,slots2[j][1])
if right_new-left_new>=duration:
return [left_new,left_new+duration]
return []
class Solution:
def minAvailableDuration(self, slots1: List[List[int]], slots2: List[List[int]], duration: int) -> List[int]:
#------------双指针
slots1.sort()
slots2.sort()
n1, n2 = len(slots1), len(slots2)
i = 0
j = 0
while i < n1 and j < n2:
s1, e1 = slots1[i]
s2, e2 = slots2[j]
s = max(s1, s2)
e = min(e1, e2)
if e - s >= duration:
return [s, s + duration]
if e1 < e2:
i += 1
else:
j += 1
return []
class Solution:
def gridIllumination(self, n: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
# 暴力模拟
# 暴力模拟
def light_dark(x, y, label):
gird[x][y] += label
# 同一行同一列设置为1,叠加,关灯的时候减去1
for j in range(n):
gird[x][j] += label
gird[x][y] -= label
for j in range(n):
gird[j][y] += label
gird[x][y] -= label
# 左对角线设置为1,左对角线上部分是(x-1,y-1),下部分是(x+1,y+1)/右对角线设置为1,右对角线上部分是(x-1,y+1),下部分是(x+1,y-1)
for j in range(1, n):
if x - j >= 0 and y - j >= 0:
gird[x - j][y - j] += label
if x + j < n and y + j < n:
gird[x + j][y + j] += label
if x - j >= 0 and y + j < n:
gird[x - j][y + j] += label
if x + j < n and y - j >= 0:
gird[x + j][y - j] += label
def check_light(x, y):
# 先检查上下左右有没有灯/上面一行,下面一行,自己的那行,到y+1
for j in range(y - 1, y + 2):
if [x - 1, j] in lamps and [x - 1, j] not in darked:
light_dark(x - 1, j, -1)
darked.append([x - 1, j])
if [x, j] in lamps and [x, j] not in darked:
light_dark(x, j, -1)
darked.append([x, j])
if [x + 1, j] in lamps and [x + 1, j] not in darked:
light_dark(x + 1, j, -1)
darked.append([x + 1, j])
gird = [[0 for _ in range(n)] for _ in range(n)]
visited = []
for i in range(len(lamps)):
if lamps[i] not in visited:
row, col = lamps[i]
light_dark(row, col, 1)
visited.append(lamps[i])
# 根据queries关灯
res = []
darked = []
for i in range(len(queries)):
row, col = queries[i]
cur_ans = gird[row][col]
# 如果是1,把四周设置为0
if cur_ans > 0:
check_light(row, col)
res.append(1)
else:
res.append(cur_ans)
return res
class Solution:
def gridIllumination(self, n: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
points = set()
row, col, diagonal, antiDiagonal = Counter(), Counter(), Counter(), Counter()
for r, c in lamps:
if (r, c) in points:
continue
points.add((r, c))
row[r] += 1
col[c] += 1
diagonal[r - c] += 1
antiDiagonal[r + c] += 1
ans = [0] * len(queries)
for i, (r, c) in enumerate(queries):
if row[r] or col[c] or diagonal[r - c] or antiDiagonal[r + c]:
ans[i] = 1
for x in range(r - 1, r + 2):
for y in range(c - 1, c + 2):
if x < 0 or y < 0 or x >= n or y >= n or (x, y) not in points:
continue
points.remove((x, y))
row[x] -= 1
col[y] -= 1
diagonal[x - y] -= 1
antiDiagonal[x + y] -= 1
return ans
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/grid-illumination/solution/wang-ge-zhao-ming-by-leetcode-solution-7omu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def countCollisions(self, directions):
"""
:type directions: str
:rtype: int
"""
# 遍历,当前是r,碰到l或者s停止,设置一个visited数组防止重复计算
count = 0
visited_index = set()
directions=list(directions)
left=0
right=len(directions)
for i in range(len(directions)):
if directions[i] == 'R':
# 往右
for j in range(i + 1, len(directions)):
if (i,j) in visited_index:
break
if directions[j] == "L" :
count += 2
visited_index.add((i,j))
directions[i] = "S"
directions[j] = "S"
break
if directions[j] == "S" :
count += 1
visited_index.add((i,j))
directions[i] = "S"
break
if directions[i] == 'L':
# 往左
for j in range(i - 1, -1, -1):
if (j,i) in visited_index:
break
# if directions[j] == "L":
# break
if directions[j] == "R":
count += 2
visited_index.add((j,i))
directions[i] = "S"
directions[j] = "S"
break
if directions[j] == "S":
count += 1
visited_index.add((j, i))
directions[i] = "S"
break
return count
class Solution {
public int countCollisions(String directions) {
char[] dirs = directions.toCharArray();
int n = dirs.length, cnt = 0;
// 统计 L 操作出现的碰撞次数
boolean leftLimit = false;
for (int i = 0; i < n; i++) {
// 左侧有车辆 S 或 R 时,说明左侧有界(L操作肯定会碰撞)
if (!leftLimit && dirs[i] != 'L') leftLimit = true;
if (dirs[i] == 'L' && leftLimit) cnt++;
}
// 统计 R 操作出现的碰撞次数
boolean rightLimit = false;
for (int i = n - 1; i >= 0; i--) {
// 右侧有车辆 S 或 L 时,说明右侧有界(R操作肯定会碰撞)
if (!rightLimit && dirs[i] != 'R') rightLimit = true;
if (dirs[i] == 'R' && rightLimit) cnt++;
}
return cnt;
}
}
作者:smqk
链接:https://leetcode-cn.com/problems/count-collisions-on-a-road/solution/by-smqk-8530/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
力扣
class Solution:
def canReorderDoubled(self, arr: List[int]) -> bool:
num_map = collections.Counter(arr)
for num in sorted(num_map, key=abs):
if num_map[num] > num_map[2 * num]:
return False
num_map[2 * num] -= num_map[num]
return True
作者:Jam007
链接:https://leetcode-cn.com/problems/array-of-doubled-pairs/solution/by-jam007-qk31/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
哈希表真牛逼,当时我是用暴力的方法,解密的时候还用了个回溯,结果超时了,最后有2个例子通不过,那个回溯应该也没法剪枝。回溯是这样的
数组[['a', 'c'], ['b'], ['a', 'c'], ['d']],在每个index的子数组里选一个数,找出所有位置的不同组合,结果例如[a,b,c,d],index 1 上取a,index 2上取b,index3上取c,index4上取d
class Encrypter:
def __init__(self, keys, values, dictionary):
self.keys = keys
self.values = values
self.dictionary = dictionary
def encrypt(self, word1: str) -> str:
res = ""
for char in word1:
index = self.keys.index(char)
replace = self.values[index]
res += replace
return res
def decrypt(self, word2: str) -> int:
# 间隔1
count = 0
all = []
for i in range(0, len(word2), 2):
cur_repalce=[]
cur = word2[i:i + 2]
#找出所有下标
values_copy = self.values.copy()
all_index = []
while cur in values_copy:
index = values_copy.index(cur)
all_index.append(index)
values_copy[index] = "-1"
for j in range(len(all_index)):
repalce = self.keys[all_index[j]]
cur_repalce.append(repalce)
all.append(cur_repalce)
print(all)
#回溯遍历所有组合情况,cur_repalce里可能有多个值
path=[]
dfs_res=[]
def dfs(index):
if index == len(all):
dfs_res.append(path[:])
return
cur = all[index]
for j in range(len(cur)):
path.append(cur[j])
dfs(index+1)
path.pop()
dfs(0)
print(dfs_res)
for i in range(len(dfs_res)):
cur = "".join(dfs_res[i])
if cur in self.dictionary:
count += 1
print(count)
return count
哈希表解法如下。真的很简洁,万事总归先可以想想能不能用map
class Encrypter {
public:
unordered_map mp;
unordered_map dicts;
Encrypter(vector& keys, vector& values, vector& dictionary) {
int n = keys.size();
for (int i = 0; i < n; i++) { /* 保存映射关系 */
mp[keys[i]] = values[i];
}
for (auto &d : dictionary) { /* 对dict加密, 计数 */
dicts[encrypt(d)]++;
}
}
string encrypt(string word1) { /* 加密 */
string ans;
for (auto &ch : word1) {
ans += mp[ch];
}
return ans;
}
int decrypt(string word2) { /* 解密, 计数 */
return dicts[word2];
}
};
作者:liu-xiang-3
链接:https://leetcode-cn.com/problems/encrypt-and-decrypt-strings/solution/c-mapshi-xian-by-liu-xiang-3-0930/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。