先来传送门:leetcode1610-可见点的最大数目
由于已经添加了传送门,故问题不再描述了哦~
题目思路:审完题后第一思路应该是通过找每个点与原点构成的角度,然后旋转题目所给角度看能一次性最多能包含多少点。所以应该先找到每个点和原点所成的夹角,然后将所有的点与原点构成的夹角都统计在一个vector中,之后采用滑动窗口去解决问题。
处理过程
- 如何生成对应的角度?以及对于该题的细节处理
答:我们通过计算每个点与起始位置的正切值来表示角度,该操作使用C++中的atan库实现
double alpha = atan(dy / dx); //返回的并非角度,而是弧度(double类型)
但仅凭借一行代码还不足以计算正确的值,以及考虑到可能会出现dx = 0的情况,于是便有了以下的处理,这里是本题比较复杂的一部分
if (dx == 0)
{
if (dy > 0) alpha = pi / 2; //y轴上半部分
else alpha = pi * 3 / 2; //y轴下半部分
}
else
{
alpha = atan(dy / dx);
if (dx < 0 && dy >= 0) alpha += pi; //第二象限
else if (dx < 0 && dy < 0) alpha += pi; //第三象限
else if (dx > 0 && dy < 0) alpha += 2 * pi; //第四象限
}
- 对生成的角度进行排序,以便于接下来使用滑动窗口
sort(angles.begin(), angles.end());
在该处应该会思考到,第四象限的点和第一象限的点之间的夹角应该是小于180度的,也就是角度是由第四象限到第一象限点之间的夹角才对,但在该vector中表现出来则是由第一象限到第四象限的角度,此时则会想到扩充生成的vector来解决此问题
int n = angles.size();
for (int i = 0; i < n; i ++ )
angles.push_back(angles[i] + 2 * pi);
- 滑动窗口实现
int i = 0, j = 0;
int ret = 0;
while (i < n && j < n)
{
while (j < n && angles[j] - angles[i] <= angle * pi / 180 + 0.0000001) //注意对于double直接判断是否相等是会有一定误差
//并且要注意题目给的是角度,需要将其转换成弧度计算
j ++;
ret = max(ret, j - i);
i += 1;
}
- 完整代码
class Solution {
public:
int visiblePoints(vector<vector<int>>& points, int angle, vector<int>& location) {
vector<double> angles;
double pi = 3.1415926;
int point = 0; //point指目标点和所给location重叠的情况,直接计数即可
for (auto t : points )
{
double dx = t[0] - location[0];
double dy = t[1] - location[1];
if (dx == 0 && dy == 0)
{
point += 1;
continue;
}
double alpha;
if (dx == 0)
{
if (dy > 0) alpha = pi / 2; //y轴上半部分
else alpha = pi * 3 / 2; //y轴下半部分
}
else
{
alpha = atan(dy / dx);
if (dx < 0 && dy >= 0) alpha += pi; //第二象限
else if (dx < 0 && dy < 0) alpha += pi; //第三象限
else if (dx > 0 && dy < 0) alpha += 2 * pi; //第四象限
}
angles.push_back(alpha);
}
sort(angles.begin(), angles.end());
int n = angles.size();
for (int i = 0; i < n; i ++ )
{
double temp = angles[i];
angles.push_back(temp + 2 * pi);
}
n = angles.size();
int i = 0, j = 0;
int ret = 0;
while (i < n && j < n)
{
while (j < n && angles[j] - angles[i] <= angle * pi / 180 + 0.0000001) j ++;
ret = max(ret, j - i);
i += 1;
}
return ret + point; //最终结果即是将滑窗最大值与point之和
}
};
最终结果还可以~
忙里偷闲写一篇题解,如果觉得对您有用请不要忘了点赞关注哦~