Max Points on a Line

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
//Definition for a point.
  struct Point {
      int x;
      int y;
      Point() : x(0), y(0) {}
      Point(int a, int b) : x(a), y(b) {}
  };
int maxPoints(vector<Point> &points) {
}

题目只有一句话:给定二维空间内的点,求在同一条直线上的最多点的数量。

分析:

1)与之前做的最小正方形的一道三分法题目很相似,但是经过分析,是没有办法是用三分法求解的;

2)两点确定一条直线,那么可以枚举任意两点所确定的一条直线,然后判断其他点是否在直线上并进行计数,求出最大点数;

  a.枚举任意两点确定一条直线时,有一个简单的优化操作,比如ponts[1],points[2]确定了一条直线,为了避免重复操作,即不出现points[2]和points[1]确定的直线被重复计算,可以再内部循环中,控制循环起点。

具体核心代码如下:

 if (points.size()==1)
        {
            return 1;
        }
        
        int result=0;

        for (int i=0;i<points.size()-1;i++)
        {
            for (int j=i+1;j<points.size();j++)
            {
                int currentNum=2;
                //cout<<"=================="<<endl;
                //cout<<"i:"<<i<<endl;
                //cout<<"j:"<<j<<endl;
                //i,j两点确定一条直线,计算直线上点的数量
                if ((points[i].x-points[j].x)!=0)
                {
                    /*这种判断方式理论上可行但是有误差
                    double k=(points[i].y-points[j].y)*1.0/(points[i].x-points[j].x);
                    double b=points[i].y-k*points[i].x;*/
                     double a=(points[i].y-points[j].y)*1.0/(points[i].x-points[j].x);
                      for (int t=0;t<points.size();t++)
                      {
                          if (t!=i&&t!=j)
                          {
                              if (points[i].x-points[t].x!=0)
                              {
                                  double b=(points[i].y-points[t].y)*1.0/(points[i].x-points[t].x);
                                  if (a==b)
                                  {
                                     /* cout<<t<<endl;*/
                                      currentNum++;
                                  }
                              }
                              else
                              {
                                  if (points[i].y==points[t].y)
                                  {
                                      /*cout<<t<<endl;*/
                                      currentNum++;
                                  }
                              }
                          }
                      }
                }
                else
                {
                    for (int t=0;t<points.size();t++)
                    {
                        if (t!=i&&t!=j)
                        {
                            if (points[t].x==points[i].x)
                            {
                                currentNum++;
                            }
                        }
                    }
                }
                if (currentNum>result)
                {
                    result=currentNum;
                }
            }
        }

提交超时,进行算法分析,整个计算过程是一个三重循环,即外层循环用于枚举直线n2,内部循环计算直线上的点n,所以最终时间复杂度是n3,接下来的算法我真是没想到,在discuss中看了别人的java代码,学习后整理自己的核心代码如下:

 vector <Point>::iterator iter;
        vector <Point>::iterator iter1;
        for (iter=points.begin();iter<points.end()-result;iter++)
        {
            int coincident=0;
            map <double,int> maxPointsInLine;
            typedef pair <double, int> line_Pair;
            for (iter1=iter+1;iter1<points.end();iter1++)
            {
                double doukey;
                //过滤重复点
                if (iter->x==iter1->x&&iter->y==iter1->y)
                {
                        coincident++;
                        continue;
                }
                //求key
                if (iter->x-iter1->x!=0)
                {
                        doukey=(iter->y-iter1->y)*1.0/(iter->x-iter1->x);
                }
                else
                {
                    doukey=0;
                }

                map <double,int>::iterator mIter;
                mIter=maxPointsInLine.find(doukey) ;
                if (mIter!=maxPointsInLine.end())
                {
                    mIter->second++;
                }
                else
                {
                    maxPointsInLine.insert(line_Pair(doukey,1));
                }
            }
            int maxp=0;
            map <double,int>::iterator mIter1;
            for (mIter1=maxPointsInLine.begin();mIter1!=maxPointsInLine.end();mIter1++)
            {
                if (maxp<mIter1->second)
                {
                    maxp=mIter1->second;
                }
            }
            if (result<maxp+coincident+1)
            {
                result=maxp+coincident+1;
            }
        }
3)算法总结:

上面的代码其实是一个时间复杂度是O(n2)的算法,算法巧妙的一点是利用了map<key,value>这个关联的容器数据结构,求解角度上也从之前的从每条直线入手,转换到以每个点为核心去求解,以为在二维空间内,通过一个点的直线,一旦其斜率确定,直线也就随之固定了,总结如下:

a.对空间中给出的每一个点,构建hash表(使用map结构),map<key,value>:key代表通过直线的斜率,value表示在这条直线上的其他点的数量(这里可以看出,map是一种关键字(key)唯一确定一个元素的数据结构);

b.对于重复点(坐标相同的点),作为冗余点设置,对其进行计数即可;

c.对于每个点来说,与改点在同一条直线上的 点的数量是:1+冗余点数量+在一条直线上的其他点的数量(也就是hash表中最大的value值)

问题出现了:这个hash表如何构建呢?

首先,没有必要针对于所有的斜率初始化构建hash表(也是没有办法构建的),因为,给定的点的数量是有限的,对于基点(构建hash表的核心点),只需每次计算其与其他“不同”点所确定的直线斜率就可以了,同时维护对应的hash表;

其次,hash表的维护,只需判断当前计算的直线斜率在hash表中是否存在,若存在更新,不存在插入。

算法中还有两个值得注意的细节:

a.最外重循环只循环了points.end()-result-points.begin()次;

b.内层循环的起点是从外重循环的下一个点开始的,原因与之前我自己想的优化思路类似,即在对points[i]进行计算时,points[j](j>i)与points[i]所确定的直线已经计算过了,说道这也就可以明白,a的优化正确行了,因为,在b的基础上,每次计算只需计算与当前基点在同一条直线上的后续点的数量,当后续节点数量小于当前的最大值时,后面再计算出的最优值肯定不会优于已经计算出的最优值,因为所有点的数量已经不够了。

表述可能不标准,还是看代码吧。。。。。。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值