leetcode1610-可见点的最大数目(C++)

本文详细解析了LeetCode第1610题,题目要求找出在给定角度下能看到的点的最大数量。解决方案是计算每个点与原点的角度,使用排序和滑动窗口算法。关键步骤包括处理点在坐标轴上的特殊情况,扩充角度范围以确保角度连续,以及使用滑动窗口找到最大连续角度内的点数。
摘要由CSDN通过智能技术生成

先来传送门:leetcode1610-可见点的最大数目
由于已经添加了传送门,故问题不再描述了哦~

题目思路:审完题后第一思路应该是通过找每个点与原点构成的角度,然后旋转题目所给角度看能一次性最多能包含多少点。所以应该先找到每个点和原点所成的夹角,然后将所有的点与原点构成的夹角都统计在一个vector中,之后采用滑动窗口去解决问题。

处理过程

  1. 如何生成对应的角度?以及对于该题的细节处理
    答:我们通过计算每个点与起始位置的正切值来表示角度,该操作使用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;	//第四象限
}
  1. 对生成的角度进行排序,以便于接下来使用滑动窗口
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);
  1. 滑动窗口实现
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;
}
  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之和
    }
};

最终结果还可以~
在这里插入图片描述
忙里偷闲写一篇题解,如果觉得对您有用请不要忘了点赞关注哦~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值