Leetcode题解 - 中等难度(1311、LCP 3、1306、1282、1296、1297)
1311. 获取你好友已观看的视频 - BFS
思路:
找到第level层的好友,是一层一层寻找所以使用BFS,然后再计数就行了
"""
BFS
"""
from collections import defaultdict, Counter
class Solution:
def watchedVideosByFriends(self, watchedVideos, friends, id: int, level: int):
mat = defaultdict(list)
# 先建图
for ind, num in enumerate(friends):
mat[ind] += num
Q, vis = [(id, 0)], {id}
# BFS找level层的朋友是谁
while len(Q) != 0:
node, deepth = Q.pop(0)
if deepth == level:
Q = [i[0] for i in Q] + [node]
break
for i in mat[node]:
if i not in vis:
vis.add(i)
Q.append((i, deepth+1))
res = []
for i in Q:
res += watchedVideos[i]
r = sorted(Counter(res).items(), key=lambda x: (x[1], x[0]))
return [i[0] for i in r]
LCP 3. 机器人大冒险
思路:
第一反映应该是模拟,当然没有这么简单,就超时了。
那么转去判断是否能够到达障碍处,这样需要判断的最多也只有1k+。
如果能够到达某处,必然是走了x轮,y步之后的结果,那么去除掉x轮走过的路,只判断这y步能否走的即可。
class Solution:
def robot(self, command: str, obstacles, x: int, y: int) -> bool:
tx, ty, res = 0, 0, []
# 记录一次command能到达的位置,如果能走到某处,去除掉x轮之后的位置必定在这里面。
for i in command:
if i == 'R':
tx += 1
if i == 'U':
ty += 1
res.append([tx, ty])
res.append([0, 0])
sorted(res)
# 判断是否能走到终点,gl表示走的轮数
gl = min(x // tx, y // ty)
if [x - gl * tx, y - gl * ty] not in res:
return False
for ox, oy in obstacles:
# 走几轮可以到这?
l = min(ox // tx, oy // ty)
# 障碍物的轮数大于目标的,那么肯定碰不到
if l > gl:
continue
# 轮数相同但是在目标位置后面也碰不着
if l == gl:
if res.index([ox - l * tx, oy - l * ty]) > res.index([x - gl * tx, y - gl * ty]):
continue
if [ox - l * tx, oy - l * ty] in res:
return False
return True
1306. 跳跃游戏 III - DFS
思路:
因为都到某个下标后都有两条路可以走 -> 想到使用DFS的模板
class Solution:
def canReach(self, arr, start: int) -> bool:
vis = set()
def DFS(node, res):
if not arr[node]:
return True
for i in [-1, 1]:
tnode = node + i * arr[node]
if judge(tnode) and tnode not in vis:
vis.add(tnode)
if DFS(tnode, res + [tnode]):
return True
vis.remove(tnode)
return False
# 判断是否出界
def judge(num):
if -1 < num < len(arr):
return True
return False
return DFS(start, [start])
1282. 用户分组
思路:
相同组大小的先放到一起,然后再根据组大小进行切割。
from collections import defaultdict
class Solution:
def groupThePeople(self, groupSizes):
res = defaultdict(list)
r = []
# 组大小相同的放在一起
for ind, group in enumerate(groupSizes):
res[group].append(ind)
# 根据组的大小进行切割
for k, v in res.items():
r += [v[i-k:i] for i in range(1, len(v)+1) if i % k == 0]
return sorted(r, key=lambda x:len(x))
1296. 划分数组为连续数字的集合
"""
通过频率来判断是否可以划分
"""
from collections import Counter
class Solution:
def isPossibleDivide(self, nums, k: int) -> bool:
# d记录所有数字出现频率
d = Counter(nums)
if len(nums) % k:
return False
for i in sorted(nums):
if d[i] <= 0:
continue
for j in range(k):
if i+j not in d or d[i+j] <= 0:
return False
d[i+j] -= 1
return True
1297. 子串的最大出现次数 - 滑动窗口
思路:
滑动窗口,窗口大小为minSize。maxSize完全就是一个迷惑项,因为但是maxSize长度的子串出现的地方,minSize长度子串必然出现,反之却不是。
from collections import Counter
class Solution:
def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:
res = []
# 先把符合条件的全部搜集起来
for i in range(0, len(s)-minSize+1):
ts = s[i:i+minSize]
if len(set(ts)) > maxLetters:
continue
else:
res.append(ts)
if not res:
return 0
# 返回出现次数最多的
return sorted(Counter(res).items(), key=lambda x:x[1], reverse=True)[0][1]