题目描述
分析
几何题,做得少,多学习学习。 (我先说我看题解这之前的想法,我可以遍历自旋角度360,然后再依次遍历点,看其是否在视野中。这其实不包对,因为题目没说自旋角度必须是整数,而且这样的复杂度在1e7的水平,力扣估计很难过掉。)
这个题目的主要做法是转成固定窗口极差的滑动窗口问题。
我们直接将题目给的所有点平移-location,这样我们之间身处极点,然后通过atan2计算出每个点p的极角(atan2相比atan好处在于,可以自动判断所在象限,但(0,0)未定义,需要额外处理)。
转化成极角(都是弧度制,取值范围[-pi,+pi]),进行排序。我们只需要看看当窗口的极差固定后,窗口中最多能包含多少元素。
有一点值得注意,普通的滑动窗口是在线性的数组进行,我们这里是一个环,而且题目要求最大视野可以是2pi,所以我们给每个点的极角加上2pi并且拼在原列表后面,这样再计算窗口元素的时候就满足首尾相接的要求了。
代码
class Solution:
def visiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int:
same = 0
p = []
for x,y in points :
if x == location[0] and y == location[1] :
same += 1
else :
p.append(atan2(y-location[1],x-location[0]))
p.sort()
# 滑动窗口 -pi ~ +pi
p += [d + 2 * pi for d in p] # 每个都加上2pi是因为视野最大有2pi的大小
p = list(map(degrees,p))
vis = 0
l = 0
for r in range(len(p)) :
while l < r and p[r]-p[l] > angle :
l += 1
# [l,r]是合法区间
vis = max(vis, r - l + 1)
return vis + same
# ---------------
class Solution:
def visiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int:
same = 0
p = []
for x,y in points :
if x == location[0] and y == location[1] :
same += 1
else :
p.append(atan2(y-location[1],x-location[0]))
p.sort()
# 滑动窗口 -pi ~ +pi
p += [d + 2 * pi for d in p]
vis = 0
l = 0
field = angle * pi / 180
for r in range(len(p)) :
while l < r and p[r]-p[l] > field :
l += 1
# [l,r]是合法区间
vis = max(vis, r - l + 1)
return vis + same