No.149 Max Point on a Line

No.149 Max Point on a Line

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

尝试1:考虑不周,一条直线上的点会重复计数,但没找到解决方法【wrong】

Input: [[0,0],[-1,-1],[2,2]]
Output: 4
Expected: 3

 1 /**
 2  * Definition for a point.
 3  * struct Point {
 4  *     int x;
 5  *     int y;
 6  *     Point() : x(0), y(0) {}
 7  *     Point(int a, int b) : x(a), y(b) {}
 8  * };
 9  */
10 class Solution 
11 {
12 public:
13     int maxPoints(vector<Point>& points)
14     {
15      //输入:二维平面上的一组点
16      //输出:同一条直线上的点的最大数量
17      //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
18      //         将得到的数据存到map中:key为斜率,value为该斜率的点的个数
19         int count = points.size() ;
20         if( count == 0)
21             return 0;
22         if( count == 1)
23             return 1;
24         if( count == 2)
25             return 2;
26         
27         map<double, int> result;
28         double slope;
29         for(int i=0; i< count ; i++)
30             for(int j = i+1; j<count; j++)
31             {
32                 if(points[i].x == points[j].x)
33                     slope = numeric_limits<double>::max();
34                 else
35                     slope = (points[i]. y - points[j]. y)/(points[i]. x - points[j]. x);//除法!!分母
36                 if(result.find(slope) == result.end())
37                     result[slope] = 2;
38                 else
39                     result[slope]++;
40             }
41         
42         int max = 0;
43         for(auto const i : result)
44         {
45             if(i.second > max)
46                 max = i.second;
47         }
48         return max;
49     }
50 
51 };
View Code

尝试2:【几次提交,总是有点小问题】

输入:二维平面上的一组点
输出:同一条直线上的点的最大数量
思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
          将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合【可以去重】

 1 /**
 2  * Definition for a point.
 3  * struct Point {
 4  *     int x;
 5  *     int y;
 6  *     Point() : x(0), y(0) {}
 7  *     Point(int a, int b) : x(a), y(b) {}
 8  * };
 9  */
10 class Solution
11 {
12 public:
13     int maxPoints(vector<Point> &points)
14     {//输入:二维平面上的一组点
15      //输出:同一条直线上的点的最大数量
16      //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
17      //         将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合
18         //const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行!!!//leetcode不支持
19         //用INT_MAX
20         int count = points.size() ;
21         if(count < 3)
22             return count;
23         map<double, set<int>> result;
24         double slope;
25         int max = 0;
26         int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i)
27         for(int i=0; i< count; i++)
28         {
29             result.clear();
30             SamePointCount = 0;
31             for(int j = 0; j<count; j++)
32             {
33                 if(i==j)
34                     continue;
35                 if(points[i].x == points[j].x && points[i].y == points[j].y)
36                 {
37                     SamePointCount++;
38                     continue;
39                 }
40                 if(points[i].x == points[j].x)
41                     slope = INT_MAX;
42                     //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关
43                 else
44                     slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母
45                     //精度问题导致错误!!!
46                 result[slope].insert(i);
47                 result[slope].insert(j);//set重复插入会无视                
48             }
49             for(auto const &i : result)
50             {
51                 if(i.second.size()+SamePointCount > max)
52                     max = i.second.size()+SamePointCount;
53             }
54         
55         }
56             return max;
57     }
58 };
View Code

 

最终:

  之前的想法与思路都是有问题的,最开始想到的,是统计每两个点确定的斜率,用哈希表来保存;之后发现,在统计斜率的时候,会有点被重复计算,就想到用一个set来保存同一斜率的点的集合;再提交,又出现问题,以为是无穷斜率需要考虑截距,其实,其他的都需要,就想,难道,要以斜率和截距来确定一条直线再统计??!!太麻烦了。

  之后,参考网上其他人的做法,找到一种比较好的做法:

  任意一条直线都可以表述为:y = ax + b
  假设,有两个点(x1,y1), (x2,y2),如果它们都在这条直线上,则有y1 = kx1 +b;y2 = kx2 +b
  由此可以得到关系,k = (y2-y1)/(x2-x1)。即如果点c和点a的斜率为k, 而点b和点a的斜率也为k,可以知道点c和点b也在一条线上。

  关键在于要有一个定点:
  取定一个点points[i], 遍历其他所有节点, 然后统计斜率相同的点数,并求取最大值即可。

  【该遍历要遍历所有,不是从i+1开始】

  注意事项:

    1、在编程过程中,若不需要,就不要存储过程或其他结果,浪费空间和时间

    2、各种测试用例的思考,多考虑,因为这个,提交好多次;要自己去想,做调试,不要等提交后,再。。

    3、修改之后,一定要做回归测试!!!

    4、特殊情况:

      1. 重复点【不要当成斜率无穷大】      
      2. 涉及除法,分母为0,斜率无穷大的情况,即与y轴平行
      3. 只有相同的点,此时直接返回即可
      4. 计算精度问题

最终版本:

 

  1 #include "stdafx.h"
  2 #include <vector>
  3 #include <map>
  4 #include <time.h>
  5 #include <iostream>
  6 #include <limits>
  7 #include <set>
  8 using namespace std;
  9 
 10 struct Point
 11 {
 12     int x;
 13     int y;
 14     Point(): x(0),y(0) {}
 15     Point(int a, int b) : x(a),y(b) {}
 16 };
 17 class Solution
 18 {
 19 public:
 20     int maxPoints(vector<Point> &points)
 21     {//输入:二维平面上的一组点
 22      //输出:同一条直线上的点的最大数量
 23      //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
 24      //         将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合
 25 //        const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行
 26         //leetcode不支持
 27         int count = points.size() ;
 28         if(count < 3)
 29             return count;
 30     
 31         map<double, int> result;
 32         double slope;
 33         int max = 0;
 34         int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i)
 35         for(int i=0; i< count; i++)
 36         {
 37             result.clear();
 38             SamePointCount = 0;
 39             for(int j = 0; j<count; j++)//
 40             {
 41                 if(i==j)//跳过相同的点
 42                     continue;
 43                 if(points[i].x == points[j].x && points[i].y == points[j].y)
 44                 {
 45                     SamePointCount++;
 46                     continue;
 47                 }
 48                 if(points[i].x == points[j].x)
 49                     slope = INT_MAX;
 50                     //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关
 51                 else
 52                     slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母
 53                     //精度问题导致错误!!!
 54                 if(result.find(slope) == result.end())
 55                     result[slope]=2;//包括该定点
 56                 else
 57                     result[slope]++;            
 58             }
 59             if(result.size() == 0)//极端:只有重复点!!!
 60                 return SamePointCount+1;
 61 
 62             for(auto const &i : result)
 63             {
 64                 if(i.second+SamePointCount > max)
 65                     max = i.second+SamePointCount;
 66             }
 67         
 68         }
 69             return max;
 70     }
 71 
 72     void generatePoints(int n , vector<Point> &points)
 73     {
 74         srand(time(0));
 75         Point p;
 76         for(int i=0; i<n; i++)
 77         {
 78             p.x = rand();
 79             p.y = rand();
 80             points.push_back(p);
 81         }
 82     }
 83 };
 84 
 85 int main()
 86 {
 87     Solution sol;
 88     vector<Point> points;
 89 //    sol.generatePoints(6,points);
 90 /*
 91     points.push_back(Point());//点(0,0)
 92     points.push_back(Point(-1,-1));//点(-1,-1)
 93     points.push_back(Point(2,2));//点(2,2)
 94     //输出应为3,却输出4,有点重复计算了!
 95 */
 96 /*
 97     //测试用例:输出应为25
 98     Point test[]= {Point(40,-23),Point(9,138),Point(429,115),Point(50,-17),Point(-3,80), Point(-10,33), Point(5,-21), Point(-3,80), Point(-6,-65), Point(-18,26), Point(-6,-65), Point(5,72), Point(0,77), Point(-9,86), Point(10,-2), Point(-8,85), Point(21,130), Point(18,-6), Point(-18,26), Point(-1,-15), Point(10,-2), Point(8,69), Point(-4,63), Point(0,3), Point(-4,40), Point(-7,84), Point(-8,7), Point(30,154), Point(16,-5), Point(6,90), Point(18,-6), Point(5,77), Point(-4,77), Point(7,-13), Point(-1,-45), Point(16,-5), Point(-9,86), Point(-16,11), Point(-7,84), Point(1,76), Point(3,77), Point(10,67), Point(1,-37), Point(-10,-81), Point(4,-11), Point(-20,13), Point(-10,77), Point(6,-17), Point(-27,2), Point(-10,-81), Point(10,-1), Point(-9,1), Point(-8,43), Point(2,2), Point(2,-21), Point(3,82), Point(8,-1), Point(10,-1), Point(-9,1), Point(-12,42), Point(16,-5), Point(-5,-61), Point(20,-7), Point(9,-35), Point(10,6), Point(12,106), Point(5,-21), Point(-5,82), Point(6,71), Point(-15,34), Point(-10,87), Point(-14,-12), Point(12,106), Point(-5,82), Point(-46,-45), Point(-4,63), Point(16,-5), Point(4,1), Point(-3,-53), Point(0,-17), Point(9,98), Point(-18,26), Point(-9,86), Point(2,77), Point(-2,-49), Point(1,76), Point(-3,-38), Point(-8,7), Point(-17,-37), Point(5,72), Point(10,-37), Point(-4,-57), Point(-3,-53), Point(3,74), Point(-3,-11), Point(-8,7), Point(1,88), Point(-12,42), Point(1,-37), Point(2,77), Point(-6,77), Point(5,72), Point(-4,-57), Point(-18,-33), Point(-12,42), Point(-9,86), Point(2,77), Point(-8,77), Point(-3,77), Point(9,-42), Point(16,41), Point(-29,-37), Point(0,-41), Point(-21,18), Point(-27,-34), Point(0,77), Point(3,74), Point(-7,-69), Point(-21,18), Point(27,146), Point(-20,13), Point(21,130), Point(-6,-65), Point(14,-4), Point(0,3), Point(9,-5), Point(6,-29), Point(-2,73), Point(-1,-15), Point(1,76), Point(-4,77), Point(6,-29)};
 99     vector<Point> points(test,test+sizeof(test)/sizeof(Point));
100     */
101 /*
102     points.push_back(Point(2,2));//
103     points.push_back(Point(2,2));//
104     points.push_back(Point(2,2));//
105 */
106 ///*
107     //测试用例:重复点问题,accept=4
108     points.push_back(Point(1,1));//0
109     points.push_back(Point(1,1));//1
110     points.push_back(Point(2,2));//2
111     points.push_back(Point(2,2));//3
112 //*/
113 
114 /*
115     //测试用例:输出应为6
116     points.push_back(Point(0,-12));//0
117     points.push_back(Point(5,2));//1
118     points.push_back(Point(2,5));//2
119     points.push_back(Point(0,-5));//3
120     points.push_back(Point(1,5));//4
121     points.push_back(Point(2,-2));//5
122     points.push_back(Point(5,-4));//6
123     points.push_back(Point(3,4));//7
124     points.push_back(Point(-2,4));//8
125     points.push_back(Point(-1,4));//9
126     points.push_back(Point(0,-5));//10
127     points.push_back(Point(0,-8));//11
128     points.push_back(Point(-2,-1));//12
129     points.push_back(Point(0,-11));//13
130     points.push_back(Point(0,-9));//14
131 */
132 
133     for(auto const &i : points)
134         cout << i.x << " "<<i.y<<endl;
135     cout << sol.maxPoints(points)<<endl;
136     return 0;
137 }

 

 最终不简洁版本:

  1 #include "stdafx.h"
  2 #include <vector>
  3 #include <map>
  4 #include <time.h>
  5 #include <iostream>
  6 #include <limits>
  7 #include <set>
  8 using namespace std;
  9 
 10 struct Point
 11 {
 12     int x;
 13     int y;
 14     Point(): x(0),y(0) {}
 15     Point(int a, int b) : x(a),y(b) {}
 16 };
 17 class Solution
 18 {
 19 public:
 20     int maxPoints(vector<Point> &points)
 21     {//输入:二维平面上的一组点
 22      //输出:同一条直线上的点的最大数量
 23      //思路:两层循环,依次找出每两个点组成的直线的斜率slope,O(n2)本以为很大,还好,相信自己
 24      //         将得到的数据存到map中:key为斜率,value为该斜率的点的索引的集合
 25 //        const double INFINITY = numeric_limits<double>::max();//无穷大斜率,即与y轴平行
 26         int count = points.size() ;
 27         if(count < 3)
 28             return count;
 29 /*
 30         if( count == 0)
 31             return 0;
 32         if( count == 1)
 33             return 1;
 34         if( count == 2)
 35             return 2;
 36 */        
 37         map<double, int> result;
 38         double slope;
 39         int max = 0;
 40         int SamePointCount = 0;//记录与当前定点i重合的点的数量(不包括i)
 41         for(int i=0; i< count; i++)
 42         {
 43             result.clear();
 44             SamePointCount = 0;
 45             for(int j = 0; j<count; j++)//
 46             {
 47                 if(i==j)//跳过相同的点
 48                     continue;
 49                 if(points[i].x == points[j].x && points[i].y == points[j].y)
 50                 {
 51                     SamePointCount++;
 52                     continue;
 53                 }
 54                 if(points[i].x == points[j].x)
 55                     slope = INT_MAX;
 56                     //此时,即使斜率相同,也不在同一条直线上,还与x(截距)有关
 57                 else
 58                     slope = (double)(points[i]. y - points[j]. y)/(double)(points[i]. x - points[j]. x);//除法!!分母
 59                     //精度问题导致错误!!!
 60                 if(result.find(slope) == result.end())
 61                     result[slope]=2;//包括该定点
 62                 else
 63                     result[slope]++;            
 64             }
 65             if(result.size() == 0)//极端:只有重复点
 66                 return SamePointCount+1;
 67 
 68             for(auto const &i : result)
 69             {
 70                 if(i.second+SamePointCount > max)
 71                     max = i.second+SamePointCount;
 72             }
 73         
 74         }
 75             return max;
 76 /*
 77         int max = 0;
 78         for(auto const i : result)
 79         {
 80             if(i.first != INFINITY && i.second.size() > max)
 81                 //斜率无穷大即与y轴垂直的,要单独计算
 82                 max = i.second.size();
 83         }
 84         if(max >=  result[INFINITY].size())
 85             return max;
 86         else
 87         {//分别计算无穷大斜率的不同截距各有几个点
 88             map<int,int> m;//key为截距,即x点坐标,value为数量
 89             for(auto i = result[INFINITY].begin(); i != result[INFINITY].end(); i++)
 90             {//set没有下标操作
 91                 if(m.find(points[*i].x) != m.end()) 
 92                     m[points[*i].x] = 1;
 93                 else
 94                     m[points[*i].x]++;
 95             }
 96             for(auto const &i : m)
 97             {
 98                 if(i.second > max)
 99                     max = i.second;
100             }
101             return max;
102         }
103 */
104     }
105 
106     void generatePoints(int n , vector<Point> &points)
107     {
108         srand(time(0));
109         Point p;
110         for(int i=0; i<n; i++)
111         {
112             p.x = rand();
113             p.y = rand();
114             points.push_back(p);
115         }
116     }
117 };
118 
119 int main()
120 {
121     Solution sol;
122     vector<Point> points;
123 //    sol.generatePoints(6,points);
124 /*
125     points.push_back(Point());//点(0,0)
126     points.push_back(Point(-1,-1));//点(-1,-1)
127     points.push_back(Point(2,2));//点(2,2)
128     //输出应为3,却输出4,有点重复计算了!
129 */
130 /*
131     //测试用例:输出应为25
132     Point test[]= {Point(40,-23),Point(9,138),Point(429,115),Point(50,-17),Point(-3,80), Point(-10,33), Point(5,-21), Point(-3,80), Point(-6,-65), Point(-18,26), Point(-6,-65), Point(5,72), Point(0,77), Point(-9,86), Point(10,-2), Point(-8,85), Point(21,130), Point(18,-6), Point(-18,26), Point(-1,-15), Point(10,-2), Point(8,69), Point(-4,63), Point(0,3), Point(-4,40), Point(-7,84), Point(-8,7), Point(30,154), Point(16,-5), Point(6,90), Point(18,-6), Point(5,77), Point(-4,77), Point(7,-13), Point(-1,-45), Point(16,-5), Point(-9,86), Point(-16,11), Point(-7,84), Point(1,76), Point(3,77), Point(10,67), Point(1,-37), Point(-10,-81), Point(4,-11), Point(-20,13), Point(-10,77), Point(6,-17), Point(-27,2), Point(-10,-81), Point(10,-1), Point(-9,1), Point(-8,43), Point(2,2), Point(2,-21), Point(3,82), Point(8,-1), Point(10,-1), Point(-9,1), Point(-12,42), Point(16,-5), Point(-5,-61), Point(20,-7), Point(9,-35), Point(10,6), Point(12,106), Point(5,-21), Point(-5,82), Point(6,71), Point(-15,34), Point(-10,87), Point(-14,-12), Point(12,106), Point(-5,82), Point(-46,-45), Point(-4,63), Point(16,-5), Point(4,1), Point(-3,-53), Point(0,-17), Point(9,98), Point(-18,26), Point(-9,86), Point(2,77), Point(-2,-49), Point(1,76), Point(-3,-38), Point(-8,7), Point(-17,-37), Point(5,72), Point(10,-37), Point(-4,-57), Point(-3,-53), Point(3,74), Point(-3,-11), Point(-8,7), Point(1,88), Point(-12,42), Point(1,-37), Point(2,77), Point(-6,77), Point(5,72), Point(-4,-57), Point(-18,-33), Point(-12,42), Point(-9,86), Point(2,77), Point(-8,77), Point(-3,77), Point(9,-42), Point(16,41), Point(-29,-37), Point(0,-41), Point(-21,18), Point(-27,-34), Point(0,77), Point(3,74), Point(-7,-69), Point(-21,18), Point(27,146), Point(-20,13), Point(21,130), Point(-6,-65), Point(14,-4), Point(0,3), Point(9,-5), Point(6,-29), Point(-2,73), Point(-1,-15), Point(1,76), Point(-4,77), Point(6,-29)};
133     vector<Point> points(test,test+sizeof(test)/sizeof(Point));
134     */
135 /*
136     points.push_back(Point(2,2));//
137     points.push_back(Point(2,2));//
138     points.push_back(Point(2,2));//
139 */
140 ///*
141     //测试用例:重复点问题,accept=4
142     points.push_back(Point(1,1));//0
143     points.push_back(Point(1,1));//1
144     points.push_back(Point(2,2));//2
145     points.push_back(Point(2,2));//3
146 //*/
147 
148 /*
149     //测试用例:输出应为6
150     points.push_back(Point(0,-12));//0
151     points.push_back(Point(5,2));//1
152     points.push_back(Point(2,5));//2
153     points.push_back(Point(0,-5));//3
154     points.push_back(Point(1,5));//4
155     points.push_back(Point(2,-2));//5
156     points.push_back(Point(5,-4));//6
157     points.push_back(Point(3,4));//7
158     points.push_back(Point(-2,4));//8
159     points.push_back(Point(-1,4));//9
160     points.push_back(Point(0,-5));//10
161     points.push_back(Point(0,-8));//11
162     points.push_back(Point(-2,-1));//12
163     points.push_back(Point(0,-11));//13
164     points.push_back(Point(0,-9));//14
165 */
166 
167     for(auto const &i : points)
168         cout << i.x << " "<<i.y<<endl;
169     cout << sol.maxPoints(points)<<endl;
170     return 0;
171 }
View Code

   

参考:

http://blog.csdn.net/linhuanmars/article/details/21060933

http://blog.csdn.net/doc_sgl/article/details/17103427

 

posted @ 2015-05-25 22:15  人生不酱油  阅读(269)  评论(0编辑  收藏  举报