【我也想刷穿 LeetCode啊】1610. 可见点的最大数目

85 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。

因此每天刷刷LeetCode非常有必要

在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode

一、题目描述

给你一个点数组 points 和一个表示角度的整数 angle ,你的位置是 location ,其中 location = [posx, posy] 且 points[i] = [xi, yi] 都表示 X-Y 平面上的整数坐标。

最开始,你面向东方进行观测。你 不能 进行移动改变位置,但可以通过 自转 调整观测角度。换句话说,posx 和 posy 不能改变。你的视野范围的角度用 angle 表示, 这决定了你观测任意方向时可以多宽。设 d 为你逆时针自转旋转的度数,那么你的视野就是角度范围 [d - angle/2, d + angle/2] 所指示的那片区域

对于每个点,如果由该点、你的位置以及从你的位置直接向东的方向形成的角度 位于你的视野中 ,那么你就可以看到它。

同一个坐标上可以有多个点。你所在的位置也可能存在一些点,但不管你的怎么旋转,总是可以看到这些点。同时,点不会阻碍你看到其他点。

返回你能看到的点的最大数目。

二、思路分析

首先算出极角并排序。算极角最简便的方法是atan2(我是看题解才知道的,我自己写的时候用的是acos+判象限)。

接下来有个问题:极角并不是一个数组而是一个环。解决方法是复制一份,加上2*PI粘贴在后面。这就是很常用的“化环为链”技巧。

排序+化环为链后,我们识别出一个经典问题:在x轴上有若干点,求一个长为k的线段最多能选中多少个点。左端点和右端点是正相关的,这就是单调性,所以双指针。

注意:与location重合的点要特殊处理

三、代码实现

var visiblePoints = function(pts, k, location) {
  let base = 0
  let init = () => {
    let tmp = []
    for (let [u, v] of pts) {
      if (u === location[0] && v === location[1]) ++base
      else tmp.push([u, v])
    }
    pts = tmp
  }
  init()
  let vec = pts.map(p => [p[0] - location[0], p[1] - location[1]])
  let a = vec.map(([x, y]) => Math.atan2(y, x))
  a = a.sort((x, y) => x - y).concat(a.map(v => v + 2 * Math.PI))
  k *= Math.PI / 180
  let ans = base
  for (let i = 0, j = 0; i < a.length; ++i) {
    while (j < a.length && a[j] <= a[i] + k) ++j
    ans = Math.max(ans, j - i + base)
  }
  return ans
};

四、总结

以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~